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

nickg / nvc / 14690659261

27 Apr 2025 09:30AM UTC coverage: 92.344% (-0.001%) from 92.345%
14690659261

push

github

nickg
Bump OSVVM to 2025.02

69222 of 74961 relevant lines covered (92.34%)

392103.3 hits per line

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

96.76
/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,356,225✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
360,485✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
82,839✔
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);
10,590,545✔
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,729✔
160
DECLARE_AND_DEFINE_ARRAY(var);
322,148✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
8,106,259✔
162
DECLARE_AND_DEFINE_ARRAY(block);
137,488✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
73,910,976✔
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,704✔
218
{
219
   int64_t result;
31,704✔
220
   if (__builtin_add_overflow(a, b, &result))
31,704✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
9,903✔
222

223
   return result;
224
}
225

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

232
   return result;
233
}
234

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

241
   return result;
242
}
243

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

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

254
   return reg;
1,351,074✔
255
}
256

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

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

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

273
   block_t *block = vcode_block_data();
1,707,066✔
274

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

281
   return op;
1,707,066✔
282
}
283

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

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

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

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

303
static op_t *vcode_find_definition(vcode_reg_t reg)
1,196,217✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
1,243,206✔
306
      block_t *b = &(active_unit->blocks.items[i]);
1,240,243✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
15,068,394✔
308
         if (b->ops.items[j].result == reg)
15,021,405✔
309
            return &(b->ops.items[j]);
1,193,254✔
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,167,717✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
1,167,717✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,167,717✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,167,717✔
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,167,717✔
331
#endif
332

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

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

346
   int depth = MASK_CONTEXT(type);
71,220,334✔
347
   assert(depth <= unit->depth);
71,220,334✔
348
   while (depth != unit->depth)
72,416,756✔
349
      unit = unit->context;
1,196,422✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
71,220,334✔
352
}
353

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

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

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

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

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

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

404
         vcode_select_unit(vu);
791✔
405

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

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

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

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

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

426
   case VCODE_OP_LOAD:
1,829✔
427
      {
428
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
1,829✔
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,057✔
433
            block_t *b = &(active_unit->blocks.items[i]);
19,474✔
434
            for (int j = 0; j < b->ops.count; j++) {
272,830✔
435
               op_t *op = &(b->ops.items[j]);
253,356✔
436
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
253,356✔
437
                  vcode_heap_allocate(op->args.items[0]);
1,583✔
438

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

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

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

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

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

537
   if (unit == active_unit)
44,934✔
538
      vcode_close();
12,201✔
539

540
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
56,209✔
541
      assert(it->context == unit);
11,275✔
542
      it->context = NULL;
11,275✔
543
   }
544
   unit->children = NULL;
44,934✔
545

546
   if (unit->context != NULL) {
44,934✔
547
      vcode_unit_t *it = &(unit->context->children);
16,842✔
548
      for (; *it != NULL && *it != unit; it = &((*it)->next))
274,336✔
549
         ;
550
      assert(*it != NULL);
16,842✔
551
      *it = (*it)->next;
16,842✔
552
   }
553

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

557
      for (unsigned j = 0; j < b->ops.count; j++) {
1,762,799✔
558
         op_t *o = &(b->ops.items[j]);
1,625,334✔
559
         if (OP_HAS_COMMENT(o->kind))
1,625,334✔
560
            free(o->comment);
169,193✔
561
         if (OP_HAS_TARGET(o->kind))
1,625,334✔
562
            free(o->targets.items);
83,154✔
563
         free(o->args.items);
1,625,334✔
564
      }
565
      free(b->ops.items);
137,465✔
566
   }
567
   free(unit->blocks.items);
44,934✔
568

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

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

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

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

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

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

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

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

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

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

621
   vtype_t *bounds = vcode_type_data(r->bounds);
700,371✔
622

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

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

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

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

646
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
296,809✔
647
         block_t *b = &(active_unit->blocks.items[i]);
229,613✔
648

649
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,242,917✔
650
            op_t *o = &(b->ops.items[j]);
3,013,304✔
651

652
            switch (o->kind) {
3,013,304✔
653
            case VCODE_OP_FCALL:
59,498✔
654
               if (o->result == VCODE_INVALID_REG)
59,498✔
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,940,370✔
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,940,370✔
700
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
191,865✔
701
                     o->comment = xasprintf("Dead %s definition of r%d",
110,507✔
702
                                            vcode_op_string(o->kind),
703
                                            o->result);
704
                     o->kind = VCODE_OP_COMMENT;
110,507✔
705
                  }
706
                  else
707
                     o->kind = (vcode_op_t)-1;
81,358✔
708
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
191,865✔
709
                  pruned++;
191,865✔
710
               }
711
               uses[o->result] = -1;
1,940,370✔
712
               break;
1,940,370✔
713

714
            default:
715
               break;
716
            }
717

718
            for (int k = 0; k < o->args.count; k++) {
7,938,613✔
719
               if (o->args.items[k] != VCODE_INVALID_REG)
4,925,309✔
720
                  uses[o->args.items[k]]++;
4,877,969✔
721
            }
722
         }
723
      }
724
   } while (pruned > 0);
67,196✔
725

726
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
182,433✔
727
      block_t *b = &(active_unit->blocks.items[i]);
137,488✔
728
      op_t *dst = &(b->ops.items[0]);
137,488✔
729
      size_t copied = 0;
137,488✔
730
      for (int j = 0; j < b->ops.count; j++) {
1,844,554✔
731
         const op_t *src = &(b->ops.items[j]);
1,707,066✔
732
         if (src->kind != (vcode_op_t)-1) {
1,707,066✔
733
            if (src != dst) {
1,625,708✔
734
               assert(dst < src);
470,770✔
735
               *dst = *src;
470,770✔
736
            }
737
            dst++;
1,625,708✔
738
            copied++;
1,625,708✔
739
         }
740
      }
741

742
      assert(copied <= b->ops.count);
137,488✔
743
      b->ops.count = copied;
137,488✔
744
   }
745
}
44,945✔
746

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

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

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

766
int vcode_count_vars(void)
43,830✔
767
{
768
   assert(active_unit != NULL);
43,830✔
769
   return active_unit->vars.count;
43,830✔
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✔
777
         return i;
×
778
   }
779

780
   return VCODE_INVALID_VAR;
781
}
782

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

930
bool vcode_block_finished(void)
1,811,620✔
931
{
932
   assert(active_unit != NULL);
1,811,620✔
933
   assert(active_block != VCODE_INVALID_BLOCK);
1,811,620✔
934

935
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,811,620✔
936
   if (b->ops.count == 0)
1,811,620✔
937
      return false;
938
   else {
939
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,630,181✔
940
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,630,181✔
941
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,630,160✔
942
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
943
         || kind == VCODE_OP_UNREACHABLE;
3,260,341✔
944
   }
945
}
946

947
const char *vcode_op_string(vcode_op_t op)
110,507✔
948
{
949
   static const char *strs[] = {
110,507✔
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))
110,507✔
979
      return "???";
980
   else
981
      return strs[op];
110,507✔
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(" nlits ");
1463
               col += vcode_dump_reg(op->args.items[1]);
1464
               vcode_dump_result_type(col, op);
1465
            }
1466
            break;
1467

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

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

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

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

1513
         case VCODE_OP_WAIT:
1514
            {
1515
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1516
                            op->targets.items[0]);
1517
               if (op->args.items[0] != VCODE_INVALID_REG) {
1518
                  printf(" for ");
1519
                  vcode_dump_reg(op->args.items[0]);
1520
               }
1521
            }
1522
            break;
1523

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2366
         color_printf("$$\n");
2367

2368
         if (callback != NULL)
2369
            (*callback)(j, arg);
2370
      }
2371

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

2376
   printf("\n");
2377
   fflush(stdout);
2378

2379
   active_block = old_block;
2380
}
2381
LCOV_EXCL_STOP
2382

2383
bool vtype_eq(vcode_type_t a, vcode_type_t b)
34,302,175✔
2384
{
2385
   assert(active_unit != NULL);
34,864,814✔
2386

2387
   if (a == b)
34,864,814✔
2388
      return true;
2389
   else {
2390
      const vtype_t *at = vcode_type_data(a);
32,238,718✔
2391
      const vtype_t *bt = vcode_type_data(b);
32,238,718✔
2392

2393
      if (at->kind != bt->kind)
32,238,718✔
2394
         return false;
2395

2396
      switch (at->kind) {
13,904,887✔
2397
      case VCODE_TYPE_INT:
11,783,602✔
2398
         return (at->low == bt->low) && (at->high == bt->high);
22,109,802✔
2399
      case VCODE_TYPE_REAL:
985,299✔
2400
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,905,300✔
2401
      case VCODE_TYPE_CARRAY:
72,700✔
2402
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
79,513✔
2403
      case VCODE_TYPE_UARRAY:
87,963✔
2404
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
110,516✔
2405
      case VCODE_TYPE_POINTER:
465,986✔
2406
      case VCODE_TYPE_ACCESS:
2407
         return vtype_eq(at->pointed, bt->pointed);
465,986✔
2408
      case VCODE_TYPE_OFFSET:
2409
      case VCODE_TYPE_OPAQUE:
2410
      case VCODE_TYPE_DEBUG_LOCUS:
2411
      case VCODE_TYPE_TRIGGER:
2412
      case VCODE_TYPE_CONVERSION:
2413
         return true;
2414
      case VCODE_TYPE_RESOLUTION:
96,653✔
2415
      case VCODE_TYPE_CLOSURE:
2416
      case VCODE_TYPE_SIGNAL:
2417
      case VCODE_TYPE_FILE:
2418
         return vtype_eq(at->base, bt->base);
96,653✔
2419
      case VCODE_TYPE_RECORD:
68,817✔
2420
      case VCODE_TYPE_CONTEXT:
2421
         return at->name == bt->name;
68,817✔
2422
      }
2423

2424
      return false;
×
2425
   }
2426
}
2427

2428
void vcode_dump(void)
×
2429
{
2430
   vcode_dump_with_mark(-1, NULL, NULL);
×
2431
}
×
2432

2433
static vcode_type_t vtype_new(vtype_t *new)
2,690,642✔
2434
{
2435
   int index = active_unit->types.count - 1;
2,690,642✔
2436
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2,690,642✔
2437

2438
   for (int i = 0; i < index; i++) {
31,966,480✔
2439
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
31,383,112✔
2440
      if (vtype_eq(this, type)) {
31,383,112✔
2441
         active_unit->types.count--;
2,107,274✔
2442
         return this;
2,107,274✔
2443
      }
2444
   }
2445

2446
   return type;
2447
}
2448

2449
vcode_type_t vtype_int(int64_t low, int64_t high)
1,766,061✔
2450
{
2451
   assert(active_unit != NULL);
1,766,061✔
2452

2453
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,766,061✔
2454
   n->kind = VCODE_TYPE_INT;
1,766,061✔
2455
   n->low  = low;
1,766,061✔
2456
   n->high = high;
1,766,061✔
2457

2458
   switch (bits_for_range(low, high)) {
1,766,061✔
2459
   case 64:
171,886✔
2460
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
171,886✔
2461
      break;
171,886✔
2462
   case 32:
542,919✔
2463
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
542,919✔
2464
      break;
542,919✔
2465
   case 16:
3,611✔
2466
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
3,611✔
2467
      break;
3,611✔
2468
   case 8:
439,201✔
2469
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
439,201✔
2470
      break;
439,201✔
2471
   case 1:
608,443✔
2472
      n->repr = VCODE_REPR_U1;
608,443✔
2473
      break;
608,443✔
2474
   case 0:
1✔
2475
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2476
      break;
1✔
2477
   default:
×
2478
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2479
   }
2480

2481
   return vtype_new(n);
1,766,061✔
2482
}
2483

2484
vcode_type_t vtype_bool(void)
305,313✔
2485
{
2486
   return vtype_int(0, 1);
305,313✔
2487
}
2488

2489
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
38,328✔
2490
{
2491
   assert(active_unit != NULL);
38,328✔
2492

2493
   const vtype_kind_t ekind = vtype_kind(elem);
38,328✔
2494
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
38,328✔
2495
                "array types may not be nested");
2496

2497
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
38,328✔
2498
   memset(n, '\0', sizeof(vtype_t));
38,328✔
2499
   n->kind   = VCODE_TYPE_CARRAY;
38,328✔
2500
   n->elem   = elem;
38,328✔
2501
   n->bounds = bounds;
38,328✔
2502
   n->size   = MAX(size, 0);
38,328✔
2503

2504
   return vtype_new(n);
38,328✔
2505
}
2506

2507
vcode_type_t vtype_find_named_record(ident_t name)
39,033✔
2508
{
2509
   assert(active_unit != NULL);
39,033✔
2510

2511
   for (int i = 0; i < active_unit->types.count; i++) {
477,108✔
2512
      vtype_t *other = &(active_unit->types.items[i]);
465,207✔
2513
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
465,207✔
2514
         return MAKE_HANDLE(active_unit->depth, i);
27,132✔
2515
   }
2516

2517
   return VCODE_INVALID_TYPE;
2518
}
2519

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

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

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

2541
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,901✔
2542
   for (int i = 0; i < nfields; i++)
31,669✔
2543
      vcode_type_array_add(&(data->fields), field_types[i]);
19,768✔
2544

2545
   return handle;
11,901✔
2546
}
2547

2548
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
82,236✔
2549
{
2550
   assert(active_unit != NULL);
82,236✔
2551

2552
   const vtype_kind_t ekind = vtype_kind(elem);
82,236✔
2553
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
82,236✔
2554
                "array types may not be nested");
2555

2556
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
82,236✔
2557

2558
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
82,236✔
2559
   memset(n, '\0', sizeof(vtype_t));
82,236✔
2560
   n->kind   = VCODE_TYPE_UARRAY;
82,236✔
2561
   n->elem   = elem;
82,236✔
2562
   n->bounds = bounds;
82,236✔
2563
   n->dims   = ndim;
82,236✔
2564

2565
   return vtype_new(n);
82,236✔
2566
}
2567

2568
vcode_type_t vtype_pointer(vcode_type_t to)
191,009✔
2569
{
2570
   assert(active_unit != NULL);
191,009✔
2571

2572
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
191,009✔
2573
   n->kind    = VCODE_TYPE_POINTER;
191,009✔
2574
   n->pointed = to;
191,009✔
2575

2576
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
191,009✔
2577
                "cannot get pointer to carray type");
2578

2579
   return vtype_new(n);
191,009✔
2580
}
2581

2582
vcode_type_t vtype_access(vcode_type_t to)
4,926✔
2583
{
2584
   assert(active_unit != NULL);
4,926✔
2585

2586
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,926✔
2587
   n->kind    = VCODE_TYPE_ACCESS;
4,926✔
2588
   n->pointed = to;
4,926✔
2589

2590
   return vtype_new(n);
4,926✔
2591
}
2592

2593
vcode_type_t vtype_signal(vcode_type_t base)
39,075✔
2594
{
2595
   assert(active_unit != NULL);
39,075✔
2596

2597
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,075✔
2598
   n->kind = VCODE_TYPE_SIGNAL;
39,075✔
2599
   n->base = base;
39,075✔
2600

2601
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
39,075✔
2602

2603
   return vtype_new(n);
39,075✔
2604
}
2605

2606
vcode_type_t vtype_resolution(vcode_type_t base)
3,690✔
2607
{
2608
   assert(active_unit != NULL);
3,690✔
2609

2610
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
3,690✔
2611
   n->kind = VCODE_TYPE_RESOLUTION;
3,690✔
2612
   n->base = base;
3,690✔
2613

2614
   return vtype_new(n);
3,690✔
2615
}
2616

2617
vcode_type_t vtype_closure(vcode_type_t result)
967✔
2618
{
2619
   assert(active_unit != NULL);
967✔
2620

2621
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
967✔
2622
   n->kind = VCODE_TYPE_CLOSURE;
967✔
2623
   n->base = result;
967✔
2624

2625
   return vtype_new(n);
967✔
2626
}
2627

2628
vcode_type_t vtype_context(ident_t name)
56,318✔
2629
{
2630
   assert(active_unit != NULL);
56,318✔
2631
   assert(name != NULL);
56,318✔
2632

2633
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
56,318✔
2634
   n->kind = VCODE_TYPE_CONTEXT;
56,318✔
2635
   n->name = name;
56,318✔
2636

2637
   return vtype_new(n);
56,318✔
2638
}
2639

2640
vcode_type_t vtype_file(vcode_type_t base)
623✔
2641
{
2642
   assert(active_unit != NULL);
623✔
2643

2644
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
623✔
2645
   n->kind = VCODE_TYPE_FILE;
623✔
2646
   n->base = base;
623✔
2647

2648
   return vtype_new(n);
623✔
2649
}
2650

2651
vcode_type_t vtype_offset(void)
257,726✔
2652
{
2653
   assert(active_unit != NULL);
257,726✔
2654

2655
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
257,726✔
2656
   n->kind = VCODE_TYPE_OFFSET;
257,726✔
2657
   n->low  = INT64_MIN;
257,726✔
2658
   n->high = INT64_MAX;
257,726✔
2659
   n->repr = VCODE_REPR_I64;
257,726✔
2660

2661
   return vtype_new(n);
257,726✔
2662
}
2663

2664
vcode_type_t vtype_time(void)
17,605✔
2665
{
2666
   return vtype_int(INT64_MIN, INT64_MAX);
17,605✔
2667
}
2668

2669
vcode_type_t vtype_char(void)
9,183✔
2670
{
2671
   return vtype_int(0, 255);
9,183✔
2672
}
2673

2674
vcode_type_t vtype_opaque(void)
1,484✔
2675
{
2676
   assert(active_unit != NULL);
1,484✔
2677

2678
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,484✔
2679
   n->kind = VCODE_TYPE_OPAQUE;
1,484✔
2680

2681
   return vtype_new(n);
1,484✔
2682
}
2683

2684
vcode_type_t vtype_debug_locus(void)
134,830✔
2685
{
2686
   assert(active_unit != NULL);
134,830✔
2687

2688
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
134,830✔
2689
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
134,830✔
2690

2691
   return vtype_new(n);
134,830✔
2692
}
2693

2694
vcode_type_t vtype_trigger(void)
395✔
2695
{
2696
   assert(active_unit != NULL);
395✔
2697

2698
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
395✔
2699
   n->kind = VCODE_TYPE_TRIGGER;
395✔
2700

2701
   return vtype_new(n);
395✔
2702
}
2703

2704
vcode_type_t vtype_conversion(void)
588✔
2705
{
2706
   assert(active_unit != NULL);
588✔
2707

2708
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
588✔
2709
   n->kind = VCODE_TYPE_CONVERSION;
588✔
2710

2711
   return vtype_new(n);
588✔
2712
}
2713

2714
vcode_type_t vtype_real(double low, double high)
106,426✔
2715
{
2716
   assert(active_unit != NULL);
106,426✔
2717

2718
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
106,426✔
2719
   n->kind  = VCODE_TYPE_REAL;
106,426✔
2720
   n->rlow  = low;
106,426✔
2721
   n->rhigh = high;
106,426✔
2722

2723
   return vtype_new(n);
106,426✔
2724
}
2725

2726
vtype_kind_t vtype_kind(vcode_type_t type)
4,148,376✔
2727
{
2728
   vtype_t *vt = vcode_type_data(type);
4,148,376✔
2729
   return vt->kind;
4,148,376✔
2730
}
2731

2732
vtype_repr_t vtype_repr(vcode_type_t type)
41,435✔
2733
{
2734
   vtype_t *vt = vcode_type_data(type);
41,435✔
2735
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
41,435✔
2736
   return vt->repr;
41,435✔
2737
}
2738

2739
vcode_type_t vtype_elem(vcode_type_t type)
121,953✔
2740
{
2741
   vtype_t *vt = vcode_type_data(type);
121,953✔
2742
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
121,953✔
2743
   return vt->elem;
121,953✔
2744
}
2745

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

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

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

2769
unsigned vtype_size(vcode_type_t type)
39,434✔
2770
{
2771
   vtype_t *vt = vcode_type_data(type);
39,434✔
2772
   assert(vt->kind == VCODE_TYPE_CARRAY);
39,434✔
2773
   return vt->size;
39,434✔
2774
}
2775

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

2783
vcode_type_t vtype_field(vcode_type_t type, int field)
31,402✔
2784
{
2785
   vtype_t *vt = vcode_type_data(type);
31,402✔
2786
   assert(vt->kind == VCODE_TYPE_RECORD);
31,402✔
2787
   return vcode_type_array_nth(&(vt->fields), field);
31,402✔
2788
}
2789

2790
ident_t vtype_name(vcode_type_t type)
21,442✔
2791
{
2792
   vtype_t *vt = vcode_type_data(type);
21,442✔
2793
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
21,442✔
2794
   return vt->name;
21,442✔
2795
}
2796

2797
vcode_type_t vtype_pointed(vcode_type_t type)
315,780✔
2798
{
2799
   vtype_t *vt = vcode_type_data(type);
315,780✔
2800
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
315,780✔
2801
   return vt->pointed;
315,780✔
2802
}
2803

2804
int64_t vtype_low(vcode_type_t type)
200,593✔
2805
{
2806
   vtype_t *vt = vcode_type_data(type);
200,593✔
2807
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
200,593✔
2808
   return vt->low;
200,593✔
2809
}
2810

2811
int64_t vtype_high(vcode_type_t type)
199,082✔
2812
{
2813
   vtype_t *vt = vcode_type_data(type);
199,082✔
2814
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
199,082✔
2815
   return vt->high;
199,082✔
2816
}
2817

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

2824
bool vtype_is_scalar(vcode_type_t type)
409,116✔
2825
{
2826
   const vtype_kind_t kind = vtype_kind(type);
409,116✔
2827
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
409,116✔
2828
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
166,375✔
2829
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2830
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2831
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2832
      || kind == VCODE_TYPE_RESOLUTION;
409,116✔
2833
}
2834

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

2841
bool vtype_is_signal(vcode_type_t type)
169,139✔
2842
{
2843
   vtype_t *vt = vcode_type_data(type);
297,907✔
2844
   switch (vt->kind) {
297,907✔
2845
   case VCODE_TYPE_SIGNAL:
2846
      return true;
2847
   case VCODE_TYPE_POINTER:
71,073✔
2848
      return vtype_is_signal(vt->pointed);
71,073✔
2849
   case VCODE_TYPE_RECORD:
2850
      for (int i = 0; i < vt->fields.count; i++) {
37,308✔
2851
         if (vtype_is_signal(vt->fields.items[i]))
29,146✔
2852
            return true;
2853
      }
2854
      return false;
2855
   case VCODE_TYPE_UARRAY:
57,695✔
2856
   case VCODE_TYPE_CARRAY:
2857
      return vtype_is_signal(vt->elem);
57,695✔
2858
   default:
132,490✔
2859
      return false;
132,490✔
2860
   }
2861
}
2862

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

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

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

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

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

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

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

2935
   return active_unit->params.count;
11,570✔
2936
}
2937

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

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

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

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

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

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

2974
vcode_block_t emit_block(void)
137,488✔
2975
{
2976
   assert(active_unit != NULL);
137,488✔
2977

2978
   vcode_block_t bnum = active_unit->blocks.count;
137,488✔
2979

2980
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
137,488✔
2981
   memset(bptr, '\0', sizeof(block_t));
137,488✔
2982

2983
   if (active_block != VCODE_INVALID_BLOCK)
137,488✔
2984
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
92,543✔
2985
   else
2986
      bptr->last_loc = LOC_INVALID;
44,945✔
2987

2988
   return bnum;
137,488✔
2989
}
2990

2991
void vcode_select_unit(vcode_unit_t unit)
159,828✔
2992
{
2993
   active_unit  = unit;
159,828✔
2994
   active_block = VCODE_INVALID_BLOCK;
159,828✔
2995
}
159,828✔
2996

2997
void vcode_select_block(vcode_block_t block)
319,970✔
2998
{
2999
   assert(active_unit != NULL);
319,970✔
3000
   active_block = block;
319,970✔
3001
}
319,970✔
3002

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

3010
const loc_t *vcode_last_loc(void)
657,360✔
3011
{
3012
   return &(vcode_block_data()->last_loc);
657,360✔
3013
}
3014

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

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

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

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

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

3045
   active_unit->result = type;
22,243✔
3046
}
22,243✔
3047

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

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

3061
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
77,895✔
3062
{
3063
   assert(vu != NULL);
77,895✔
3064
   return vu->context;
77,895✔
3065
}
3066

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

3073
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
57,344✔
3074
{
3075
   int hops = 0;
57,344✔
3076
   for (; (unit = unit->context); hops++)
147,110✔
3077
      ;
3078
   return hops;
57,344✔
3079
}
3080

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

3085
   child->next = NULL;
28,120✔
3086
   if (context->children == NULL)
28,120✔
3087
      context->children = child;
11,377✔
3088
   else {
3089
      vcode_unit_t it;
3090
      for (it = context->children; it->next != NULL; it = it->next)
737,842✔
3091
         ;
3092
      it->next = child;
16,743✔
3093
   }
3094
}
28,120✔
3095

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

3106
   vcode_add_child(context, vu);
11,266✔
3107

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

3112
   return vu;
11,266✔
3113
}
3114

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

3125
   vcode_add_child(context, vu);
257✔
3126

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

3131
   return vu;
257✔
3132
}
3133

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

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

3147
   vcode_add_child(context, vu);
9,284✔
3148

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

3153
   return vu;
9,284✔
3154
}
3155

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

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

3168
   if (context != NULL)
9,446✔
3169
      vcode_add_child(context, vu);
5,811✔
3170

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

3175
   return vu;
9,446✔
3176
}
3177

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

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

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

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

3197
   return vu;
89✔
3198
}
3199

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

3210
   if (context != NULL)
1,805✔
3211
      vcode_add_child(context, vu);
186✔
3212

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

3217
   return vu;
1,805✔
3218
}
3219

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

3230
   if (context != NULL)
177✔
3231
      vcode_add_child(context, vu);
177✔
3232

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

3237
   return vu;
177✔
3238
}
3239

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

3250
   if (context != NULL)
222✔
3251
      vcode_add_child(context, vu);
222✔
3252

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

3257
   return vu;
222✔
3258
}
3259

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

3271
   if (context != NULL)
12,399✔
3272
      vcode_add_child(context, vu);
917✔
3273

3274
   vcode_select_unit(vu);
12,399✔
3275
   vcode_select_block(emit_block());
12,399✔
3276

3277
   return vu;
12,399✔
3278
}
3279

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

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

3297
   if (hint_left != VCODE_INVALID_REG) {
14,011✔
3298
      vcode_add_arg(op, hint_left);
5,837✔
3299
      vcode_add_arg(op, hint_right);
5,837✔
3300

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

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

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

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

3335
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
37,260✔
3336
{
3337
   if (lhs == rhs) {
37,260✔
3338
      if (cmp == VCODE_CMP_EQ)
934✔
3339
         return emit_const(vtype_bool(), 1);
927✔
3340
      else if (cmp == VCODE_CMP_NEQ)
7✔
3341
         return emit_const(vtype_bool(), 0);
×
3342
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
3343
         return emit_const(vtype_bool(), 1);
×
3344
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3345
         return emit_const(vtype_bool(), 0);
7✔
3346
   }
3347

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

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

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

3381
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
35,614✔
3382
                "arguments to cmp are not the same type");
3383

3384
   return op->result;
3385
}
3386

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

3396
   for (int i = 0; i < nargs; i++)
143,408✔
3397
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
106,712✔
3398
                   "invalid argument to function");
3399

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

3403
   if (type == VCODE_INVALID_TYPE)
36,696✔
3404
      return (o->result = VCODE_INVALID_REG);
4,963✔
3405
   else {
3406
      o->result = vcode_add_reg(type);
31,733✔
3407

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

3411
      return o->result;
31,733✔
3412
   }
3413
}
3414

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

3423
   vcode_block_array_add(&(o->targets), resume_bb);
892✔
3424

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

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

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

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

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

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

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

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

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

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

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

3478
   return op->result;
7,206✔
3479
}
3480

3481
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
989,579✔
3482
{
3483
   // Reuse any previous constant in this block with the same type and value
3484
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
19,398,061✔
3485
      if (other->value == value && vtype_eq(type, other->type))
7,257,872✔
3486
         return other->result;
585,078✔
3487
   }
3488

3489
   op_t *op = vcode_add_op(VCODE_OP_CONST);
404,501✔
3490
   op->value  = value;
404,501✔
3491
   op->type   = type;
404,501✔
3492
   op->result = vcode_add_reg(type);
404,501✔
3493

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

3498
   reg_t *r = vcode_reg_data(op->result);
404,501✔
3499
   r->bounds = vtype_int(value, value);
404,501✔
3500

3501
   return op->result;
404,501✔
3502
}
3503

3504
vcode_reg_t emit_const_real(vcode_type_t type, double value)
63,973✔
3505
{
3506
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,606,345✔
3507
      if (other->real == value && other->type == type)
938,269✔
3508
         return other->result;
23,669✔
3509
   }
3510

3511
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
40,304✔
3512
   op->real   = value;
40,304✔
3513
   op->type   = type;
40,304✔
3514
   op->result = vcode_add_reg(op->type);
40,304✔
3515

3516
   reg_t *r = vcode_reg_data(op->result);
40,304✔
3517
   r->bounds = vtype_real(value, value);
40,304✔
3518

3519
   return op->result;
40,304✔
3520
}
3521

3522
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
28,633✔
3523
{
3524
   vtype_kind_t kind = vtype_kind(type);
28,633✔
3525

3526
   // Reuse any previous operation in this block with the same arguments
3527
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,159,102✔
3528
      if (other->args.count != num)
114,071✔
3529
         continue;
68,496✔
3530
      else if (!vtype_eq(vcode_reg_type(other->result), type))
45,575✔
3531
         continue;
661✔
3532

3533
      bool match = true;
3534
      for (int i = 0; match && i < num; i++) {
269,849✔
3535
         if (other->args.items[i] != values[i])
224,935✔
3536
            match = false;
38,792✔
3537
      }
3538

3539
      if (match) return other->result;
44,914✔
3540
   }
3541

3542
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
22,511✔
3543
   op->result = vcode_add_reg(type);
22,511✔
3544

3545
   for (int i = 0; i < num; i++)
1,183,417✔
3546
      vcode_add_arg(op, values[i]);
1,160,906✔
3547

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

3553
#ifdef DEBUG
3554
   vcode_type_t elem = vtype_elem(type);
22,511✔
3555
   for (int i = 0; i < num; i++) {
1,183,417✔
3556
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,160,906✔
3557
                   "wrong element type for item %d", i);
3558
      vcode_assert_const(values[i], "array");
1,160,906✔
3559
   }
3560
#endif
3561

3562
   reg_t *r = vcode_reg_data(op->result);
22,511✔
3563
   r->bounds = vtype_elem(type);
22,511✔
3564

3565
   return op->result;
22,511✔
3566
}
3567

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

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

3580
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
355✔
3581
                "constant array must have constrained array type");
3582
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
355✔
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,790✔
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) {
41,065✔
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,564✔
3609
   op->type   = type;
2,564✔
3610
   op->result = vcode_add_reg(type);
2,564✔
3611

3612
   for (int i = 0; i < num; i++)
9,020✔
3613
      vcode_add_arg(op, values[i]);
6,456✔
3614

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

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

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

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

3632
vcode_reg_t emit_address_of(vcode_reg_t value)
30,470✔
3633
{
3634
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,227,165✔
3635
      if (other->args.items[0] == value)
115,295✔
3636
         return other->result;
6,153✔
3637
   }
3638

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

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

3646
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
24,317✔
3647
      vcode_type_t elem = vtype_elem(type);
22,297✔
3648
      op->result = vcode_add_reg(vtype_pointer(elem));
22,297✔
3649

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

3653
      return op->result;
22,297✔
3654
   }
3655
   else
3656
      return (op->result = vcode_add_reg(vtype_pointer(type)));
2,020✔
3657
}
3658

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

3665
   VCODE_ASSERT(time == VCODE_INVALID_REG
13,798✔
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,798✔
3669
                || active_unit->kind == VCODE_UNIT_PROCESS,
3670
                "wait only allowed in process or procedure");
3671
}
13,798✔
3672

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

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

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

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

3694
   return var;
49,477✔
3695
}
3696

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

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

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

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

3714
vcode_reg_t emit_load(vcode_var_t var)
50,737✔
3715
{
3716
   // Try scanning backwards through the block for another load or store to
3717
   // this variable
3718
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
50,737✔
3719
   vcode_reg_t fold = VCODE_INVALID_REG;
50,737✔
3720
   VCODE_FOR_EACH_OP(other) {
738,314✔
3721
      switch (state) {
701,551✔
3722
      case EAGER:
237,250✔
3723
         if (other->kind == VCODE_OP_LOAD && other->address == var)
237,250✔
3724
            return other->result;
3,014✔
3725
         else if (other->kind == VCODE_OP_STORE && other->address == var)
234,236✔
3726
            return other->args.items[0];
10,960✔
3727
         else if (other->kind == VCODE_OP_FCALL
223,276✔
3728
                  || other->kind == VCODE_OP_PCALL
223,276✔
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,815✔
3734
         break;
3735

3736
      case CONSERVATIVE:
438,661✔
3737
         if (other->kind == VCODE_OP_LOAD && other->address == var
438,661✔
3738
             && fold == VCODE_INVALID_REG)
4,212✔
3739
            fold = other->result;
3,366✔
3740
         else if (other->kind == VCODE_OP_STORE && other->address == var
435,295✔
3741
                  && fold == VCODE_INVALID_REG)
2,579✔
3742
            fold = other->args.items[0];
2,436✔
3743
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
432,859✔
3744
            state = UNSAFE;
3745
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
431,878✔
3746
            state = UNSAFE;   // Nested call captures variables
92✔
3747
         break;
3748

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

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

3757
   var_t *v = vcode_var_data(var);
31,320✔
3758

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

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

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

3768
   return op->result;
31,320✔
3769
}
3770

3771
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
97,803✔
3772
{
3773
   VCODE_FOR_EACH_OP(other) {
1,073,612✔
3774
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,006,612✔
3775
          && other->args.items[0] == reg) {
157,277✔
3776
         return other->result;
7,294✔
3777
      }
3778
      else if (other->kind == VCODE_OP_FCALL
999,318✔
3779
               || other->kind == VCODE_OP_PCALL
999,318✔
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);
90,509✔
3789
   vcode_add_arg(op, reg);
90,509✔
3790

3791
   vcode_type_t rtype = vcode_reg_type(reg);
90,509✔
3792

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

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

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

3801
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
90,509✔
3802

3803
   return op->result;
90,509✔
3804
}
3805

3806
void emit_store(vcode_reg_t reg, vcode_var_t var)
58,261✔
3807
{
3808
   // Any previous store to this variable in this block is dead
3809
   VCODE_FOR_EACH_OP(other) {
1,142,165✔
3810
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,095,224✔
3811
         other->kind = VCODE_OP_COMMENT;
329✔
3812
         other->comment =
658✔
3813
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
329✔
3814
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
329✔
3815
      }
3816
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,094,895✔
3817
         break;   // Needs to get variable for display
3818
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,088,950✔
3819
               && other->address == var)
24,120✔
3820
         break;   // Previous value may be used
3821
   }
3822

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

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

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

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

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

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

3851
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
50,441✔
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,125,992✔
3856
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
56,001✔
3857
         return other->result;
3,658✔
3858
   }
3859

3860
   op_t *op = vcode_add_op(kind);
46,783✔
3861
   vcode_add_arg(op, lhs);
46,783✔
3862
   vcode_add_arg(op, rhs);
46,783✔
3863
   if (locus != VCODE_INVALID_REG)
46,783✔
3864
      vcode_add_arg(op, locus);
3,976✔
3865

3866
   op->result = vcode_add_reg(vcode_reg_type(lhs));
46,783✔
3867

3868
   vcode_type_t lhs_type = vcode_reg_type(lhs);
46,783✔
3869
   vcode_type_t rhs_type = vcode_reg_type(rhs);
46,783✔
3870

3871
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
46,783✔
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,
41,653✔
3878
                               vcode_reg_t locus)
3879
{
3880
   int64_t lconst, rconst;
41,653✔
3881
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
41,653✔
3882
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
41,653✔
3883
   if (l_is_const && r_is_const)
41,653✔
3884
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
23,737✔
3885
   else if (r_is_const && rconst == 1)
17,916✔
3886
      return lhs;
3887
   else if (l_is_const && lconst == 1)
3,623✔
3888
      return rhs;
3889
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
3,097✔
3890
      return emit_const(vcode_reg_type(lhs), 0);
57✔
3891

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

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

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

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

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

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

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

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

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

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

3933
   return reg;
3934
}
3935

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

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

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

3948
   return result;
879✔
3949
}
3950

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

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

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

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

3974
   return reg;
3975
}
3976

3977
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
78✔
3978
{
3979
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
78✔
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)
190✔
4001
{
4002
   int64_t lconst, rconst;
190✔
4003
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
190✔
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);
187✔
4008
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
187✔
4009

4010
   if (bl->low >= 0 && br->low >= 0) {
187✔
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);
55✔
4014

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

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

4024
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
80✔
4025
{
4026
   int64_t lconst, rconst;
80✔
4027
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
80✔
4028
       && lconst > 0 && rconst > 0)
2✔
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);
80✔
4032

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

4036
   if (bl->low >= 0 && br->low >= 0) {
80✔
4037
      reg_t *rr = vcode_reg_data(reg);
34✔
4038
      rr->bounds = vtype_int(0, br->high - 1);
34✔
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,
42,345✔
4045
                               vcode_reg_t locus)
4046
{
4047
   int64_t lconst, rconst;
42,345✔
4048
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
42,345✔
4049
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
42,345✔
4050
   if (l_is_const && r_is_const)
42,345✔
4051
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,531✔
4052
   else if (r_is_const && rconst == 0)
25,814✔
4053
      return lhs;
4054
   else if (l_is_const && lconst == 0)
25,744✔
4055
      return rhs;
4056

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

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

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

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

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

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

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

4082
   return reg;
4083
}
4084

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

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

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

4097
   return result;
2,810✔
4098
}
4099

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

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

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

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

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

4130
      vbounds = vtype_int(rbl, rbh);
23,262✔
4131
   }
4132

4133
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
23,562✔
4134

4135
   if (vbounds != VCODE_INVALID_TYPE)
23,562✔
4136
      vcode_reg_data(reg)->bounds = vbounds;
23,262✔
4137

4138
   return reg;
4139
}
4140

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

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

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

4153
   return result;
5,654✔
4154
}
4155

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

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

4170
   case VCODE_TYPE_INT:
43,658✔
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
   case VCODE_TYPE_RESOLUTION:
4181
      op->type = vtype_pointer(var->type);
43,658✔
4182
      op->result = vcode_add_reg(op->type);
43,658✔
4183
      vcode_reg_data(op->result)->bounds = var->bounds;
43,658✔
4184
      break;
43,658✔
4185

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

4192
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
23,009✔
4193
{
4194
   // Try to find a previous index of this var by this offset
4195
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
783,633✔
4196
      if (other->address == var
50,744✔
4197
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,377✔
4198
              || (offset != VCODE_INVALID_REG
×
4199
                  && other->args.items[0] == offset)))
×
4200
         return other->result;
7,377✔
4201
   }
4202

4203
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
15,632✔
4204
   op->address = var;
15,632✔
4205

4206
   if (offset != VCODE_INVALID_REG)
15,632✔
4207
      vcode_add_arg(op, offset);
×
4208

4209
   vcode_calculate_var_index_type(op, vcode_var_data(var));
15,632✔
4210

4211
   if (offset != VCODE_INVALID_REG)
15,632✔
4212
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4213
                   "index offset r%d does not have offset type", offset);
4214

4215
   return op->result;
15,632✔
4216
}
4217

4218
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
208,665✔
4219
{
4220
   if (vtype_eq(vcode_reg_type(reg), type))
208,665✔
4221
      return reg;
208,665✔
4222

4223
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
78,900✔
4224
   vtype_kind_t to   = vtype_kind(type);
78,900✔
4225

4226
   const bool integral =
157,800✔
4227
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
78,900✔
4228
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
78,900✔
4229

4230
   int64_t value;
78,900✔
4231
   if (integral && vcode_reg_const(reg, &value))
78,900✔
4232
      return emit_const(type, value);
16,219✔
4233

4234
   // Try to find a previous cast of this register to this type
4235
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,281,738✔
4236
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
139,221✔
4237
         return other->result;
14,303✔
4238
   }
4239

4240
   op_t *op = vcode_add_op(VCODE_OP_CAST);
48,378✔
4241
   vcode_add_arg(op, reg);
48,378✔
4242
   op->type   = type;
48,378✔
4243
   op->result = vcode_add_reg(type);
48,378✔
4244

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

4255
   if (integral) {
48,378✔
4256
      vtype_t *vt = vcode_type_data(type);
47,712✔
4257
      int64_t low = vt->low, high = vt->high;
47,712✔
4258

4259
      vtype_t *rt = vcode_type_data(vcode_reg_bounds(reg));
47,712✔
4260
      low = MAX(low, rt->low);
47,712✔
4261
      high = MIN(high, rt->high);
47,712✔
4262

4263
      if (bounds != VCODE_INVALID_REG) {
47,712✔
4264
         vtype_t *bt = vcode_type_data(bounds);
32,451✔
4265
         low = MAX(low, bt->low);
32,451✔
4266
         high = MIN(high, bt->high);
32,451✔
4267
      }
4268

4269
      reg_t *rr = vcode_reg_data(op->result);
47,712✔
4270
      rr->bounds = vtype_int(low, high);
47,712✔
4271
   }
4272
   else if (bounds != VCODE_INVALID_REG)
666✔
4273
      vcode_reg_data(op->result)->bounds = bounds;
666✔
4274

4275
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
88,465✔
4276
      if (from == allowed[i][0] && to == allowed[i][1])
88,465✔
4277
         return op->result;
48,378✔
4278
   }
4279

4280
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4281
}
4282

4283
void emit_return(vcode_reg_t reg)
53,704✔
4284
{
4285
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
53,704✔
4286
   if (reg != VCODE_INVALID_REG) {
53,704✔
4287
      vcode_add_arg(op, reg);
28,899✔
4288

4289
      const vtype_kind_t rkind = vcode_reg_kind(reg);
28,899✔
4290
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
28,899✔
4291
         vcode_heap_allocate(reg);
8,045✔
4292

4293
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
28,899✔
4294
                   || active_unit->kind == VCODE_UNIT_THUNK
4295
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4296
                   "returning value fron non-function unit");
4297
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
28,899✔
4298
                    && rkind == VCODE_TYPE_INT)
4299
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4300
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4301
                       && rkind == VCODE_TYPE_ACCESS),
4302
                   "return value incorrect type");
4303
   }
4304
}
53,704✔
4305

4306
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
10,780✔
4307
                         vcode_reg_t values, vcode_reg_t reject,
4308
                         vcode_reg_t after)
4309
{
4310
   int64_t nconst;
10,780✔
4311
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
10,780✔
4312
      emit_comment("Skip empty waveform");
9✔
4313
      return;
9✔
4314
   }
4315

4316
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
10,771✔
4317
   vcode_add_arg(op, nets);
10,771✔
4318
   vcode_add_arg(op, nnets);
10,771✔
4319
   vcode_add_arg(op, values);
10,771✔
4320
   vcode_add_arg(op, reject);
10,771✔
4321
   vcode_add_arg(op, after);
10,771✔
4322

4323
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
10,771✔
4324
                "sched_waveform target is not signal");
4325
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
10,771✔
4326
                "sched_waveform net count is not offset type");
4327
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
10,771✔
4328
                "signal cannot be values argument for sched_waveform");
4329
}
4330

4331
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
63✔
4332
{
4333
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
63✔
4334
   vcode_add_arg(op, nets);
63✔
4335
   vcode_add_arg(op, nnets);
63✔
4336
   vcode_add_arg(op, values);
63✔
4337

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

4344
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
30✔
4345
{
4346
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
30✔
4347
   vcode_add_arg(op, nets);
30✔
4348
   vcode_add_arg(op, nnets);
30✔
4349

4350
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
30✔
4351
                "release target is not signal");
4352
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
30✔
4353
                "release net count is not offset type");
4354
}
30✔
4355

4356
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
24✔
4357
                     vcode_reg_t after)
4358
{
4359
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
24✔
4360
   vcode_add_arg(op, nets);
24✔
4361
   vcode_add_arg(op, nnets);
24✔
4362
   vcode_add_arg(op, reject);
24✔
4363
   vcode_add_arg(op, after);
24✔
4364

4365
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4366
                "disconnect target is not signal");
4367
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4368
                "disconnect net count is not offset type");
4369
}
24✔
4370

4371
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
35,808✔
4372
{
4373
   int64_t tconst;
35,808✔
4374
   if (vcode_reg_const(test, &tconst)) {
35,808✔
4375
      emit_jump(!!tconst ? btrue : bfalse);
4,812✔
4376
      return;
2,837✔
4377
   }
4378

4379
   op_t *op = vcode_add_op(VCODE_OP_COND);
32,971✔
4380
   vcode_add_arg(op, test);
32,971✔
4381
   vcode_add_target(op, btrue);
32,971✔
4382
   vcode_add_target(op, bfalse);
32,971✔
4383

4384
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
32,971✔
4385
                "cond test is not a bool");
4386
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
32,971✔
4387
                "invalid cond targets");
4388
}
4389

4390
vcode_reg_t emit_neg(vcode_reg_t lhs)
7,338✔
4391
{
4392
   int64_t lconst;
7,338✔
4393
   if (vcode_reg_const(lhs, &lconst))
7,338✔
4394
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4395

4396
   op_t *op = vcode_add_op(VCODE_OP_NEG);
7,338✔
4397
   vcode_add_arg(op, lhs);
7,338✔
4398
   op->result = vcode_add_reg(vcode_reg_type(lhs));
7,338✔
4399

4400
   return op->result;
7,338✔
4401
}
4402

4403
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
775✔
4404
{
4405
   int64_t lconst;
775✔
4406
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
775✔
4407
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4408
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
775✔
4409
      return emit_neg(lhs);   // Cannot overflow
222✔
4410

4411
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
553✔
4412
   vcode_add_arg(op, lhs);
553✔
4413
   vcode_add_arg(op, locus);
553✔
4414

4415
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
553✔
4416
                "locus argument to trap neg must be a debug locus");
4417
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
553✔
4418
                "trapping neg may only be used with integer types");
4419

4420
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
553✔
4421
}
4422

4423
vcode_reg_t emit_abs(vcode_reg_t lhs)
236✔
4424
{
4425
   int64_t lconst;
236✔
4426
   if (vcode_reg_const(lhs, &lconst))
236✔
4427
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4428

4429
   op_t *op = vcode_add_op(VCODE_OP_ABS);
235✔
4430
   vcode_add_arg(op, lhs);
235✔
4431
   op->result = vcode_add_reg(vcode_reg_type(lhs));
235✔
4432

4433
   return op->result;
235✔
4434
}
4435

4436
void emit_comment(const char *fmt, ...)
58,372✔
4437
{
4438
#ifndef NDEBUG
4439
   va_list ap;
58,372✔
4440
   va_start(ap, fmt);
58,372✔
4441

4442
   char *buf = xvasprintf(fmt, ap);
58,372✔
4443
   for (char *p = buf + strlen(buf) - 1;
58,372✔
4444
        p >= buf && isspace_iso88591(*p); p--)
58,372✔
4445
      *p = '\0';
×
4446

4447
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
58,372✔
4448
   va_end(ap);
58,372✔
4449
#endif
4450
}
58,372✔
4451

4452
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,375✔
4453
                        vcode_reg_t rfalse)
4454
{
4455
   int64_t tconst;
18,375✔
4456
   if (vcode_reg_const(test, &tconst))
18,375✔
4457
      return !!tconst ? rtrue : rfalse;
4,386✔
4458
   else if (rtrue == rfalse)
13,989✔
4459
      return rtrue;
4460

4461
   // Find a previous identical select
4462
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
303,490✔
4463
      if (other->args.items[0] == test && other->args.items[1] == rtrue
12,488✔
4464
          && other->args.items[2] == rfalse)
699✔
4465
         return other->result;
638✔
4466
   }
4467

4468
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
13,114✔
4469
   vcode_add_arg(op, test);
13,114✔
4470
   vcode_add_arg(op, rtrue);
13,114✔
4471
   vcode_add_arg(op, rfalse);
13,114✔
4472
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
13,114✔
4473

4474
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
13,114✔
4475
                "select test must have bool type");
4476
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
13,114✔
4477
                "select arguments are not the same type");
4478

4479
   return op->result;
13,114✔
4480
}
4481

4482
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
388✔
4483
{
4484
   switch (op) {
388✔
4485
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
24✔
4486
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
316✔
4487
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4488
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4489
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4490
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4491
   default:
×
4492
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4493
   }
4494
}
4495

4496
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
6,279✔
4497
{
4498
   vcode_type_t vtbool = vtype_bool();
6,279✔
4499

4500
   int64_t lconst, rconst;
6,279✔
4501
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
6,279✔
4502
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
6,279✔
4503
   if (l_is_const && r_is_const) {
6,279✔
4504
      switch (op) {
6✔
4505
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4506
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4507
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4508
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
4509
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4510
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4511
      default:
×
4512
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4513
      }
4514
   }
4515
   else if (l_is_const)
6,273✔
4516
      return emit_logical_identity(op, rhs, !!lconst);
309✔
4517
   else if (r_is_const)
5,964✔
4518
      return emit_logical_identity(op, lhs, !!rconst);
79✔
4519
   else if (lhs == rhs) {
5,885✔
4520
      switch (op) {
27✔
4521
      case VCODE_OP_AND:
4522
      case VCODE_OP_OR:
4523
         return lhs;
4524
      case VCODE_OP_NAND:
6✔
4525
      case VCODE_OP_NOR:
4526
         return emit_not(lhs);
6✔
4527
      case VCODE_OP_XOR:
3✔
4528
         return emit_const(vtbool, 0);
3✔
4529
      case VCODE_OP_XNOR:
×
4530
         return emit_const(vtbool, 1);
×
4531
      default:
×
4532
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4533
      }
4534
   }
4535

4536
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
5,858✔
4537

4538
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
5,858✔
4539
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4540
                "arguments to %s are not boolean", vcode_op_string(op));
4541

4542
   return result;
4543
}
4544

4545
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,114✔
4546
{
4547
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,114✔
4548
}
4549

4550
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
3,809✔
4551
{
4552
   return emit_logical(VCODE_OP_AND, lhs, rhs);
3,809✔
4553
}
4554

4555
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
77✔
4556
{
4557
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
77✔
4558
}
4559

4560
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
78✔
4561
{
4562
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
78✔
4563
}
4564

4565
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
119✔
4566
{
4567
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
119✔
4568
}
4569

4570
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
82✔
4571
{
4572
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
82✔
4573
}
4574

4575
vcode_reg_t emit_not(vcode_reg_t arg)
2,727✔
4576
{
4577
   int64_t cval;
2,727✔
4578
   if (vcode_reg_const(arg, &cval))
2,727✔
4579
      return emit_const(vtype_bool(), !cval);
27✔
4580

4581
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,700✔
4582
   vcode_add_arg(op, arg);
2,700✔
4583

4584
   vcode_type_t vtbool = vtype_bool();
2,700✔
4585
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,700✔
4586
                "argument to not is not boolean");
4587

4588
   return (op->result = vcode_add_reg(vtbool));
2,700✔
4589
}
4590

4591
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
47,086✔
4592
{
4593
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,597,029✔
4594
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
146,847✔
4595
         bool match = true;
4596
         for (int i = 0; match && i < ndims; i++) {
19,750✔
4597
            match = other->args.items[i*3 + 1] == dims[i].left
9,904✔
4598
               && other->args.items[i*3 + 2] == dims[i].right
8,440✔
4599
               && other->args.items[i*3 + 3] == dims[i].dir;
18,090✔
4600
         }
4601
         if (match)
9,846✔
4602
            return other->result;
8,128✔
4603
      }
4604
   }
4605

4606
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
38,958✔
4607
   vcode_add_arg(op, data);
38,958✔
4608
   for (int i = 0; i < ndims; i++) {
78,448✔
4609
      vcode_add_arg(op, dims[i].left);
39,490✔
4610
      vcode_add_arg(op, dims[i].right);
39,490✔
4611
      vcode_add_arg(op, dims[i].dir);
39,490✔
4612
   }
4613

4614
   vcode_type_t ptr_type = vcode_reg_type(data);
38,958✔
4615
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
38,958✔
4616
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
38,958✔
4617
                "wrapped data is not pointer or signal");
4618

4619
#ifdef DEBUG
4620
   for (int i = 0; i < ndims; i++) {
78,448✔
4621
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
39,490✔
4622
                   "dimension %d left bound must be scalar", i + 1);
4623
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
39,490✔
4624
                   "dimension %d right bound must be scalar", i + 1);
4625
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
39,490✔
4626
                   "dimension %d direction must be bool", i + 1);
4627
   }
4628
#endif
4629

4630
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
77,916✔
4631
      ? vtype_pointed(ptr_type) : ptr_type;
38,958✔
4632

4633
   op->result = vcode_add_reg(
38,958✔
4634
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4635

4636
   return op->result;
38,958✔
4637
}
4638

4639
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
115,000✔
4640
                                  vcode_reg_t array, unsigned dim,
4641
                                  unsigned arg_index)
4642
{
4643
   // Reuse any previous operation in this block with the same arguments
4644
   VCODE_FOR_EACH_OP(other) {
1,209,758✔
4645
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,159,852✔
4646
          && (rtype == VCODE_INVALID_TYPE
22,885✔
4647
              || vtype_eq(rtype, vcode_reg_type(other->result))))
9,629✔
4648
         return other->result;
22,885✔
4649
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,136,967✔
4650
         return other->args.items[1 + (dim * 3) + arg_index];
42,209✔
4651
   }
4652

4653
   op_t *op = vcode_add_op(o);
49,906✔
4654
   vcode_add_arg(op, array);
49,906✔
4655
   op->dim = dim;
49,906✔
4656

4657
   vcode_type_t atype = vcode_reg_type(array);
49,906✔
4658
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
49,906✔
4659
                "cannot use %s with non-uarray type", vcode_op_string(o));
4660

4661
   vtype_t *vt = vcode_type_data(atype);
49,906✔
4662
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
49,906✔
4663

4664
   if (rtype == VCODE_INVALID_TYPE)
49,906✔
4665
      rtype = vtype_offset();
32,503✔
4666

4667
   return (op->result = vcode_add_reg(rtype));
49,906✔
4668
}
4669

4670
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
41,472✔
4671
{
4672
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
41,472✔
4673
                         array, dim, 0);
4674
}
4675

4676
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
32,381✔
4677
{
4678
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
32,381✔
4679
                         array, dim, 1);
4680
}
4681

4682
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
41,147✔
4683
{
4684
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
41,147✔
4685
                         array, dim, 2);
4686
}
4687

4688
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
49,107✔
4689
{
4690
   VCODE_FOR_EACH_OP(other) {
534,479✔
4691
      if (other->kind == VCODE_OP_UARRAY_LEN) {
510,226✔
4692
         if (other->args.items[0] == array && other->dim == dim)
34,199✔
4693
            return other->result;
10,293✔
4694
      }
4695
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
476,027✔
4696
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,561✔
4697
                      "array dimension %d out of bounds", dim);
4698

4699
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,561✔
4700
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,561✔
4701
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,561✔
4702
         return emit_range_length(left_reg, right_reg, dir_reg);
14,561✔
4703
      }
4704
   }
4705

4706
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
24,253✔
4707
   vcode_add_arg(op, array);
24,253✔
4708
   op->dim = dim;
24,253✔
4709

4710
   vcode_type_t atype = vcode_reg_type(array);
24,253✔
4711
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
24,253✔
4712
                "cannot use uarray len with non-uarray type");
4713

4714
   vtype_t *vt = vcode_type_data(atype);
24,253✔
4715
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
24,253✔
4716

4717
   op->result = vcode_add_reg(vtype_offset());
24,253✔
4718

4719
   reg_t *rr = vcode_reg_data(op->result);
24,253✔
4720
   rr->bounds = vtype_int(0, INT64_MAX);
24,253✔
4721

4722
   return op->result;
24,253✔
4723
}
4724

4725
vcode_reg_t emit_unwrap(vcode_reg_t array)
37,909✔
4726
{
4727
   VCODE_FOR_EACH_OP(other) {
1,403,271✔
4728
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,376,236✔
4729
         return other->args.items[0];
9,438✔
4730
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,366,798✔
4731
         return other->result;
1,436✔
4732
   }
4733

4734
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
27,035✔
4735
   vcode_add_arg(op, array);
27,035✔
4736

4737
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
27,035✔
4738
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
27,035✔
4739
                "unwrap can only only be used with uarray types");
4740

4741
   vcode_type_t elem = vt->elem;
27,035✔
4742

4743
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
27,035✔
4744
      ? elem : vtype_pointer(elem);
27,035✔
4745

4746
   op->result = vcode_add_reg(rtype);
27,035✔
4747

4748
   reg_t *rr = vcode_reg_data(op->result);
27,035✔
4749
   rr->bounds = elem;
27,035✔
4750

4751
   return op->result;
27,035✔
4752
}
4753

4754
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
18,755✔
4755
                            vcode_reg_t dir)
4756
{
4757
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
623,732✔
4758
      if (other->args.items[0] == left
×
4759
          && other->args.items[1] == right
×
4760
          && other->args.items[2] == dir)
×
4761
         return other->result;
×
4762
   }
4763

4764
   int64_t dir_const;
18,755✔
4765
   if (vcode_reg_const(dir, &dir_const)) {
18,755✔
4766
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
14,172✔
4767
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
14,172✔
4768

4769
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
14,172✔
4770
         return emit_const(vtype_bool(), 1);
50✔
4771
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
14,122✔
4772
         return emit_const(vtype_bool(), 0);
7,445✔
4773
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,677✔
4774
         return emit_const(vtype_bool(), 1);
121✔
4775
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
6,556✔
4776
         return emit_const(vtype_bool(), 0);
1,773✔
4777
      else if (dir_const == RANGE_TO)
4,783✔
4778
         return emit_cmp(VCODE_CMP_GT, left, right);
1,487✔
4779
      else
4780
         return emit_cmp(VCODE_CMP_GT, right, left);
3,296✔
4781
   }
4782

4783
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,583✔
4784
   vcode_add_arg(op, left);
4,583✔
4785
   vcode_add_arg(op, right);
4,583✔
4786
   vcode_add_arg(op, dir);
4,583✔
4787

4788
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,583✔
4789
                "range left and right have different types");
4790
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,583✔
4791
                "dir argument to range length is not int");
4792

4793
   return (op->result = vcode_add_reg(vtype_bool()));
4,583✔
4794
}
4795

4796
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,593✔
4797
                              vcode_reg_t dir)
4798
{
4799
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,593✔
4800
      right_array = VCODE_INVALID_REG,
14,593✔
4801
      dir_array = VCODE_INVALID_REG;
14,593✔
4802
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,593✔
4803

4804
   VCODE_FOR_EACH_OP(other) {
304,000✔
4805
      if (other->kind == VCODE_OP_RANGE_LENGTH
294,342✔
4806
          && other->args.items[0] == left
6,619✔
4807
          && other->args.items[1] == right
5,303✔
4808
          && other->args.items[2] == dir)
4,935✔
4809
         return other->result;
4,935✔
4810
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
289,407✔
4811
         left_array = other->args.items[0];
342✔
4812
         left_dim = other->dim;
342✔
4813
      }
4814
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
289,065✔
4815
         right_array = other->args.items[0];
342✔
4816
         right_dim = other->dim;
342✔
4817
      }
4818
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
288,723✔
4819
         dir_array = other->args.items[0];
1,079✔
4820
         dir_dim = other->dim;
1,079✔
4821
      }
4822
   }
4823

4824
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,658✔
4825
       && right_array == dir_array && left_dim == right_dim
342✔
4826
       && right_dim == dir_dim)
342✔
4827
      return emit_uarray_len(left_array, left_dim);
342✔
4828

4829
   int64_t lconst, rconst, dconst;
9,316✔
4830
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
9,316✔
4831
       && vcode_reg_const(right, &rconst)) {
5,173✔
4832

4833
      int64_t diff;
2,928✔
4834
      if (dconst == RANGE_TO)
2,928✔
4835
         diff = rconst - lconst;
2,608✔
4836
      else
4837
         diff = lconst - rconst;
320✔
4838

4839
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,928✔
4840
   }
4841

4842
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
6,388✔
4843
   vcode_add_arg(op, left);
6,388✔
4844
   vcode_add_arg(op, right);
6,388✔
4845
   vcode_add_arg(op, dir);
6,388✔
4846

4847
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
6,388✔
4848
                "range left and right have different types");
4849
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
6,388✔
4850
                "dir argument to range length is not int");
4851

4852
   op->result = vcode_add_reg(vtype_offset());
6,388✔
4853

4854
   reg_t *rr = vcode_reg_data(op->result);
6,388✔
4855
   rr->bounds = vtype_int(0, INT64_MAX);
6,388✔
4856

4857
   return op->result;
6,388✔
4858
}
4859

4860
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
53,975✔
4861
{
4862
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
463,719✔
4863
      if (other->hops == hops && other->address == var)
62,053✔
4864
         return other->result;
7,620✔
4865
   }
4866

4867
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
46,355✔
4868
   op->hops    = hops;
46,355✔
4869
   op->address = var;
46,355✔
4870

4871
   VCODE_ASSERT(hops > 0, "invalid hop count");
46,355✔
4872

4873
   vcode_unit_t vu = active_unit;
46,355✔
4874
   for (int i = 0; i < hops; i++) {
103,460✔
4875
      vu = vu->context;
57,105✔
4876
      VCODE_ASSERT(vu, "hop count is greater than depth");
57,105✔
4877
   }
4878

4879
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
46,355✔
4880

4881
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
46,355✔
4882

4883
   return op->result;
46,355✔
4884
}
4885

4886
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
15,925✔
4887
                             vcode_reg_t size, vcode_reg_t value,
4888
                             vcode_reg_t flags, vcode_reg_t locus,
4889
                             vcode_reg_t offset)
4890
{
4891
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
15,925✔
4892
   vcode_add_arg(op, count);
15,925✔
4893
   vcode_add_arg(op, size);
15,925✔
4894
   vcode_add_arg(op, value);
15,925✔
4895
   vcode_add_arg(op, flags);
15,925✔
4896
   vcode_add_arg(op, locus);
15,925✔
4897
   if (offset != VCODE_INVALID_REG)
15,925✔
4898
      vcode_add_arg(op, offset);
5,607✔
4899

4900
   vcode_type_t vtype = vcode_reg_type(value);
15,925✔
4901
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
15,925✔
4902
   VCODE_ASSERT(vtype_eq(vtype, type)
15,925✔
4903
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4904
                "init signal value type does not match signal type");
4905
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
15,925✔
4906
                "locus argument to init signal must be a debug locus");
4907
   VCODE_ASSERT(offset == VCODE_INVALID_REG
15,925✔
4908
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4909
                "init signal offset argument must have pointer type");
4910

4911
   return (op->result = vcode_add_reg(vtype_signal(type)));
15,925✔
4912
}
4913

4914
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,320✔
4915
{
4916
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,320✔
4917
   vcode_add_arg(op, signal);
3,320✔
4918
   vcode_add_arg(op, resolution);
3,320✔
4919

4920
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,320✔
4921
                "signal argument has wrong type");
4922
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
3,320✔
4923
                "resolution wrapper argument has wrong type");
4924
}
3,320✔
4925

4926
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
81✔
4927
                                 vcode_reg_t size, vcode_reg_t locus,
4928
                                 vcode_reg_t kind, vcode_reg_t closure,
4929
                                 vcode_reg_t delay)
4930
{
4931
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
81✔
4932
   vcode_add_arg(op, count);
81✔
4933
   vcode_add_arg(op, size);
81✔
4934
   vcode_add_arg(op, locus);
81✔
4935
   vcode_add_arg(op, kind);
81✔
4936
   vcode_add_arg(op, closure);
81✔
4937
   vcode_add_arg(op, delay);
81✔
4938

4939
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
81✔
4940
                "count argument to implicit signal is not offset");
4941
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
81✔
4942
                "kind argument to implicit signal is not offset");
4943
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
81✔
4944
                "closure argument to implicit signal is not a closure");
4945
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
81✔
4946
                "locus argument to implicit signal must be a debug locus");
4947
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
81✔
4948
                "delay argument to implicit signal must be time");
4949

4950
   return (op->result = vcode_add_reg(vtype_signal(type)));
81✔
4951
}
4952

4953
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,314✔
4954
{
4955
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,314✔
4956
   vcode_add_arg(op, src);
5,314✔
4957
   vcode_add_arg(op, dst);
5,314✔
4958
   vcode_add_arg(op, count);
5,314✔
4959

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

4968
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
216✔
4969
{
4970
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
216✔
4971
   vcode_add_arg(op, src);
216✔
4972
   vcode_add_arg(op, dst);
216✔
4973
   vcode_add_arg(op, count);
216✔
4974

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

4981
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
63✔
4982
{
4983
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
63✔
4984
   vcode_add_arg(op, src);
63✔
4985
   vcode_add_arg(op, dst);
63✔
4986
   vcode_add_arg(op, count);
63✔
4987

4988
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
63✔
4989
                "src argument to map implicit is not a signal");
4990
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
63✔
4991
                "dst argument to map implicit is not a signal");
4992
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
63✔
4993
                "count argument type to map implicit is not offset");
4994
}
63✔
4995

4996
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
9,395✔
4997
{
4998
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
114,948✔
4999
      if (other->args.items[0] == target && other->args.items[1] == count)
13,844✔
5000
         return;
5001
   }
5002

5003
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
9,371✔
5004
   vcode_add_arg(op, target);
9,371✔
5005
   vcode_add_arg(op, count);
9,371✔
5006

5007
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
9,371✔
5008
                "target argument to drive signal is not a signal");
5009
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,371✔
5010
                "count argument type to drive signal is not offset");
5011
}
5012

5013
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,209✔
5014
                          vcode_reg_t count, vcode_reg_t reject,
5015
                          vcode_reg_t after)
5016
{
5017
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,209✔
5018
   vcode_add_arg(op, target);
1,209✔
5019
   vcode_add_arg(op, source);
1,209✔
5020
   vcode_add_arg(op, count);
1,209✔
5021
   vcode_add_arg(op, reject);
1,209✔
5022
   vcode_add_arg(op, after);
1,209✔
5023

5024
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,209✔
5025
                "target argument to transfer signal is not a signal");
5026
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,209✔
5027
                "count argument type to transfer signal is not offset");
5028
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,209✔
5029
                "source argument to transfer signal is not a signal");
5030
}
1,209✔
5031

5032
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
583✔
5033
                                    vcode_reg_t nlits)
5034
{
5035
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
12,842✔
5036
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
1,855✔
5037
         return other->result;
×
5038
   }
5039

5040
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
583✔
5041
                "first argument to resolution wrapper must be closure");
5042

5043
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
583✔
5044
   vcode_add_arg(op, closure);
583✔
5045
   vcode_add_arg(op, nlits);
583✔
5046

5047
   return (op->result = vcode_add_reg(vtype_resolution(type)));
583✔
5048
}
5049

5050
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
967✔
5051
                         vcode_type_t rtype)
5052
{
5053
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
22,343✔
5054
      if (other->func == func && other->args.items[0] == context)
2,203✔
5055
         return other->result;
×
5056
   }
5057

5058
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
967✔
5059
   vcode_add_arg(op, context);
967✔
5060
   op->func = func;
967✔
5061
   op->type = atype;
967✔
5062

5063
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
967✔
5064
                "invalid closure context argument");
5065

5066
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
967✔
5067
}
5068

5069
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
33,771✔
5070
{
5071
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
52,108✔
5072
      if (other->func == name)
25,324✔
5073
         return other->result;
12,819✔
5074
   }
5075

5076
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
20,952✔
5077
   op->func = name;
20,952✔
5078
   if (context != VCODE_INVALID_REG)
20,952✔
5079
      vcode_add_arg(op, context);
187✔
5080

5081
   VCODE_ASSERT(context == VCODE_INVALID_REG
20,952✔
5082
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5083
                "invalid protected init context argument");
5084
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
20,952✔
5085
                || active_unit->kind == VCODE_UNIT_PACKAGE
5086
                || active_unit->kind == VCODE_UNIT_THUNK,
5087
                "cannot use package init here");
5088
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
20,952✔
5089

5090
   return (op->result = vcode_add_reg(vtype_context(name)));
20,952✔
5091
}
5092

5093
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
167✔
5094
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5095
{
5096
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
167✔
5097
   vcode_add_arg(op, context);
167✔
5098
   op->func = vtype_name(type);
167✔
5099

5100
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
167✔
5101
      vcode_add_arg(op, path_name);
38✔
5102
      vcode_add_arg(op, inst_name);
38✔
5103

5104
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
38✔
5105
                   "path name argument must be uarray");
5106
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
38✔
5107
                   "inst name argument must be uarray");
5108
   }
5109

5110
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
167✔
5111
                "protected init type must be context");
5112
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
167✔
5113
                "invalid protected init context argument");
5114

5115
   return (op->result = vcode_add_reg(type));
167✔
5116
}
5117

5118
void emit_process_init(ident_t name, vcode_reg_t locus)
110✔
5119
{
5120
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
110✔
5121
   vcode_add_arg(op, locus);
110✔
5122
   op->func = name;
110✔
5123

5124
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
110✔
5125
                "locus argument to process init must be a debug locus");
5126
}
110✔
5127

5128
void emit_protected_free(vcode_reg_t obj)
7✔
5129
{
5130
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
5131
   vcode_add_arg(op, obj);
7✔
5132

5133
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
5134
                "protected object type must be context");
5135
}
7✔
5136

5137
vcode_reg_t emit_context_upref(int hops)
16,528✔
5138
{
5139
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
117,122✔
5140
      if (other->hops == hops)
7,487✔
5141
         return other->result;
7,428✔
5142
   }
5143

5144
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
9,100✔
5145
   op->hops = hops;
9,100✔
5146

5147
   VCODE_ASSERT(hops >= 0, "invalid hop count");
9,100✔
5148

5149
   vcode_unit_t vu = active_unit;
9,100✔
5150
   for (int i = 0; i < hops; i++) {
17,327✔
5151
      vu = vu->context;
8,227✔
5152
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,227✔
5153
   }
5154

5155
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
9,100✔
5156
}
5157

5158
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
595✔
5159
                                    vcode_reg_t len)
5160
{
5161
   op_t *op = vcode_add_op(opkind);
595✔
5162
   vcode_add_arg(op, nets);
595✔
5163
   vcode_add_arg(op, len);
595✔
5164

5165
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
595✔
5166
                "argument to %s is not a signal", vcode_op_string(opkind));
5167

5168
   return (op->result = vcode_add_reg(vtype_bool()));
595✔
5169
}
5170

5171
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
375✔
5172
{
5173
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
375✔
5174
}
5175

5176
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
220✔
5177
{
5178
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
220✔
5179
}
5180

5181
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
41,815✔
5182
{
5183
   // Try scanning backwards through the block for another record ref
5184
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,802,820✔
5185
      if (other->args.items[0] == record && other->field == field)
517,826✔
5186
         return other->result;
3,913✔
5187
   }
5188

5189
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
37,902✔
5190
   op->field = field;
37,902✔
5191
   vcode_add_arg(op, record);
37,902✔
5192

5193
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
37,902✔
5194

5195
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
37,902✔
5196
                "argument to record ref must be a pointer");
5197

5198
   vtype_t *rtype = vcode_type_data(rptype->pointed);
37,902✔
5199
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
37,902✔
5200
                "argument must be pointer to record or record signal");
5201

5202
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
37,902✔
5203

5204
   vcode_type_t field_type  = rtype->fields.items[field];
37,902✔
5205
   vcode_type_t bounds_type = field_type;
37,902✔
5206
   vcode_type_t result_type = field_type;
37,902✔
5207

5208
   const vtype_kind_t fkind = vtype_kind(field_type);
37,902✔
5209
   if (fkind == VCODE_TYPE_CARRAY)
37,902✔
5210
      result_type = bounds_type = vtype_elem(field_type);
5,139✔
5211
   else if (fkind == VCODE_TYPE_UARRAY) {
32,763✔
5212
      bounds_type = vtype_elem(field_type);
2,823✔
5213
      result_type = field_type;
2,823✔
5214
   }
5215

5216
   op->result = vcode_add_reg(vtype_pointer(result_type));
37,902✔
5217

5218
   reg_t *rr = vcode_reg_data(op->result);
37,902✔
5219
   rr->bounds = bounds_type;
37,902✔
5220

5221
   return op->result;
37,902✔
5222
}
5223

5224
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
34,513✔
5225
{
5226
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,492,300✔
5227
      if (other->args.items[0] == array && other->args.items[1] == offset)
95,009✔
5228
         return other->result;
1,199✔
5229
   }
5230

5231
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
33,314✔
5232
   vcode_add_arg(op, array);
33,314✔
5233
   vcode_add_arg(op, offset);
33,314✔
5234

5235
   vcode_type_t rtype = vcode_reg_type(array);
33,314✔
5236
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
33,314✔
5237
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5238
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5239
                "argument to array ref must be a pointer or signal");
5240
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
33,314✔
5241
                "array ref offset argument must have offset type");
5242

5243
   op->result = vcode_add_reg(rtype);
33,314✔
5244

5245
   reg_t *rr = vcode_reg_data(op->result);
33,314✔
5246
   rr->bounds = vcode_reg_bounds(array);
33,314✔
5247

5248
   return op->result;
33,314✔
5249
}
5250

5251
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
20,958✔
5252
{
5253
   int64_t cconst;
20,958✔
5254
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
20,958✔
5255
       && cconst == 0)
10,694✔
5256
      return;
4,931✔
5257
   else if (dest == src)
20,782✔
5258
      return;
5259

5260
   op_t *op = vcode_add_op(VCODE_OP_COPY);
16,027✔
5261
   vcode_add_arg(op, dest);
16,027✔
5262
   vcode_add_arg(op, src);
16,027✔
5263
   if (count != VCODE_INVALID_REG)
16,027✔
5264
      vcode_add_arg(op, count);
14,205✔
5265

5266
   vcode_type_t dtype = vcode_reg_type(dest);
16,027✔
5267
   vcode_type_t stype = vcode_reg_type(src);
16,027✔
5268

5269
   vtype_kind_t dkind = vtype_kind(dtype);
16,027✔
5270
   vtype_kind_t skind = vtype_kind(stype);
16,027✔
5271

5272
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
16,027✔
5273
                "destination type is not a pointer or access");
5274
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
16,027✔
5275
                "source type is not a pointer or access");
5276
   VCODE_ASSERT(vtype_eq(dtype, stype),
16,027✔
5277
                "source and destination types do not match");
5278
   VCODE_ASSERT(count == VCODE_INVALID_REG
16,027✔
5279
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5280
                "count is not offset type");
5281

5282
   op->type = vtype_pointed(dtype);
16,027✔
5283
}
5284

5285
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,950✔
5286
{
5287
   VCODE_FOR_EACH_OP(other) {
99,136✔
5288
      if (other->kind == VCODE_OP_CLEAR_EVENT)
93,240✔
5289
         break;
5290
      else if (other->kind == VCODE_OP_SCHED_EVENT
93,192✔
5291
               && other->args.items[0] == nets
4,784✔
5292
               && other->args.items[1] == n_elems)
9✔
5293
         return;
5294
   }
5295

5296
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,944✔
5297
   vcode_add_arg(op, nets);
5,944✔
5298
   vcode_add_arg(op, n_elems);
5,944✔
5299

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

5304
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
528✔
5305
{
5306
   VCODE_FOR_EACH_OP(other) {
2,424✔
5307
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,896✔
5308
         break;
5309
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,896✔
5310
               && other->args.items[0] == nets
39✔
5311
               && other->args.items[1] == n_elems)
×
5312
         return;
5313
   }
5314

5315
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
528✔
5316
   vcode_add_arg(op, nets);
528✔
5317
   vcode_add_arg(op, n_elems);
528✔
5318

5319
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
528✔
5320
                "nets argument to clear event must be signal");
5321
}
5322

5323
void emit_resume(ident_t func)
892✔
5324
{
5325
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
892✔
5326
   op->func = func;
892✔
5327

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

5332
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,664✔
5333
{
5334
   int64_t lconst;
5,664✔
5335
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,664✔
5336
      return;
29✔
5337

5338
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,635✔
5339
   vcode_add_arg(op, ptr);
5,635✔
5340
   vcode_add_arg(op, value);
5,635✔
5341
   vcode_add_arg(op, len);
5,635✔
5342

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

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

5357
   for (int i = 0; i < ncases; i++) {
5,303✔
5358
      bool can_fold = false;
4,663✔
5359
      if (cases[i] == value)
4,663✔
5360
         can_fold = true;
5361
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,663✔
5362
         can_fold = (cval1 == cval2);
4✔
5363

5364
      if (can_fold) {
4✔
5365
         emit_jump(blocks[i]);
4✔
5366
         return;
8✔
5367
      }
5368
   }
5369

5370
   if (is_const) {
640✔
5371
      emit_jump(def);
×
5372
      return;
×
5373
   }
5374

5375
   op_t *op = vcode_add_op(VCODE_OP_CASE);
640✔
5376
   vcode_add_arg(op, value);
640✔
5377
   vcode_add_target(op, def);
640✔
5378

5379
   for (int i = 0; i < ncases; i++) {
5,299✔
5380
      vcode_add_arg(op, cases[i]);
4,659✔
5381
      vcode_add_target(op, blocks[i]);
4,659✔
5382

5383
#ifdef DEBUG
5384
      for (int j = 0; j < i; j++)
244,703✔
5385
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
240,044✔
5386
#endif
5387
   }
5388
}
5389

5390
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
268✔
5391
                    vcode_reg_t kind, vcode_reg_t status)
5392
{
5393
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
268✔
5394
   vcode_add_arg(op, file);
268✔
5395
   vcode_add_arg(op, name);
268✔
5396
   vcode_add_arg(op, length);
268✔
5397
   vcode_add_arg(op, kind);
268✔
5398
   if (status != VCODE_INVALID_REG)
268✔
5399
      vcode_add_arg(op, status);
26✔
5400

5401
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
268✔
5402
                "file open first argument must have file pointer type");
5403
}
268✔
5404

5405
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
123✔
5406
{
5407
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
123✔
5408
   vcode_add_arg(op, file);
123✔
5409
   vcode_add_arg(op, value);
123✔
5410
   if (length != VCODE_INVALID_REG)
123✔
5411
      vcode_add_arg(op, length);
66✔
5412

5413
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
123✔
5414
                "file write first argument must have file pointer type");
5415
}
123✔
5416

5417
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
75✔
5418
                    vcode_reg_t inlen, vcode_reg_t outlen)
5419
{
5420
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
75✔
5421
   vcode_add_arg(op, file);
75✔
5422
   vcode_add_arg(op, ptr);
75✔
5423
   if (inlen != VCODE_INVALID_REG) {
75✔
5424
      vcode_add_arg(op, inlen);
27✔
5425
      if (outlen != VCODE_INVALID_REG)
27✔
5426
         vcode_add_arg(op, outlen);
18✔
5427
   }
5428

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

5438
vcode_reg_t emit_null(vcode_type_t type)
10,592✔
5439
{
5440
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
249,226✔
5441
      if (vtype_eq(vcode_reg_type(other->result), type))
5,010✔
5442
         return other->result;
2,560✔
5443
   }
5444

5445
   op_t *op = vcode_add_op(VCODE_OP_NULL);
8,032✔
5446
   op->result = vcode_add_reg(type);
8,032✔
5447

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

5453
   return op->result;
5454
}
5455

5456
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
423✔
5457
{
5458
   op_t *op = vcode_add_op(VCODE_OP_NEW);
423✔
5459
   if (length != VCODE_INVALID_REG)
423✔
5460
      vcode_add_arg(op, length);
332✔
5461

5462
   op->result = vcode_add_reg(vtype_access(type));
423✔
5463

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

5473
   return op->result;
423✔
5474
}
5475

5476
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,745✔
5477
{
5478
   VCODE_FOR_EACH_OP(other) {
108,845✔
5479
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
107,733✔
5480
         return;
5481
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
107,353✔
5482
         return;
5483
   }
5484

5485
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,112✔
5486
   vcode_add_arg(op, ptr);
1,112✔
5487
   vcode_add_arg(op, locus);
1,112✔
5488

5489
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,112✔
5490
                "null check argument must be an access");
5491
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,112✔
5492
                "locus argument to null check must be a debug locus");
5493
}
5494

5495
void emit_deallocate(vcode_reg_t ptr)
203✔
5496
{
5497
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
203✔
5498
   vcode_add_arg(op, ptr);
203✔
5499

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

5506
vcode_reg_t emit_all(vcode_reg_t reg)
2,168✔
5507
{
5508
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
152,404✔
5509
      if (other->args.items[0] == reg)
9,509✔
5510
         return other->result;
633✔
5511
   }
5512

5513
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,535✔
5514
   vcode_add_arg(op, reg);
1,535✔
5515

5516
   vcode_type_t vtype = vcode_reg_type(reg);
1,535✔
5517

5518
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,535✔
5519
                "all argument must be an access");
5520

5521
   vcode_type_t pointed = vtype_pointed(vtype);
1,535✔
5522
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,535✔
5523

5524
   reg_t *rr = vcode_reg_data(op->result);
1,535✔
5525
   rr->bounds = pointed;
1,535✔
5526

5527
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,535✔
5528
                "cannot dereference opaque type");
5529

5530
   return op->result;
5531
}
5532

5533
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
14,925✔
5534
{
5535
   block_t *b = &(active_unit->blocks.items[active_block]);
14,925✔
5536
   for (int i = b->ops.count - 1; i >= 0; i--) {
371,424✔
5537
      const op_t *other = &(b->ops.items[i]);
357,054✔
5538
      if (other->kind == kind && other->args.items[0] == sig)
357,054✔
5539
         return other->result;
555✔
5540
   }
5541

5542
   op_t *op = vcode_add_op(kind);
14,370✔
5543
   vcode_add_arg(op, sig);
14,370✔
5544

5545
   vcode_type_t stype = vcode_reg_type(sig);
14,370✔
5546
   op->type = stype;
14,370✔
5547

5548
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
14,370✔
5549
                "argument r%d to resolved is not a signal", sig);
5550

5551
   vcode_type_t rtype = vtype_base(stype);
14,370✔
5552

5553
   const vtype_kind_t rkind = vtype_kind(rtype);
14,370✔
5554
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
14,370✔
5555
      rtype = vtype_elem(rtype);
×
5556

5557
   VCODE_ASSERT(vtype_is_scalar(rtype),
14,370✔
5558
                "resolved signal base type must be scalar");
5559

5560
   op->result = vcode_add_reg(vtype_pointer(rtype));
14,370✔
5561

5562
   reg_t *rr = vcode_reg_data(op->result);
14,370✔
5563
   rr->bounds = rtype;
14,370✔
5564

5565
   return op->result;
14,370✔
5566
}
5567

5568
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
14,839✔
5569
{
5570
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
14,839✔
5571
}
5572

5573
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
86✔
5574
{
5575
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
86✔
5576
}
5577

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

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

5591
   return (op->result = vcode_add_reg(vtype_time()));
66✔
5592
}
5593

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

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

5607
   return (op->result = vcode_add_reg(vtype_time()));
69✔
5608
}
5609

5610
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,202✔
5611
{
5612
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,202✔
5613
   vcode_add_arg(op, signal);
4,202✔
5614
   vcode_add_arg(op, locus);
4,202✔
5615

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

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

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

5633
   return (op->result = vcode_add_reg(vtype_bool()));
36✔
5634
}
5635

5636
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
173✔
5637
{
5638
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
173✔
5639
   vcode_add_arg(op, signal);
173✔
5640
   if (len != VCODE_INVALID_REG)
173✔
5641
      vcode_add_arg(op, len);
33✔
5642

5643
   vcode_type_t signal_type = vcode_reg_type(signal);
173✔
5644

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

5651
   vcode_type_t base_type = vtype_base(signal_type);
173✔
5652
   op->result = vcode_add_reg(vtype_pointer(base_type));
173✔
5653

5654
   reg_t *rr = vcode_reg_data(op->result);
173✔
5655
   rr->bounds = base_type;
173✔
5656

5657
   return op->result;
173✔
5658
}
5659

5660
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
21,369✔
5661
                       vcode_reg_t dim)
5662
{
5663
   if (rlen == llen)
21,369✔
5664
      return;
5665

5666
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
191,072✔
5667
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,851✔
5668
         return;
5669
   }
5670

5671
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
6,788✔
5672
   vcode_add_arg(op, llen);
6,788✔
5673
   vcode_add_arg(op, rlen);
6,788✔
5674
   vcode_add_arg(op, locus);
6,788✔
5675
   if (dim != VCODE_INVALID_REG)
6,788✔
5676
      vcode_add_arg(op, dim);
27✔
5677

5678
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6,788✔
5679
                "locus argument to length check must be a debug locus");
5680
}
5681

5682
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
816✔
5683
{
5684
   int64_t cval;
816✔
5685
   if (vcode_reg_const(exp, &cval) && cval >= 0)
816✔
5686
      return;
299✔
5687

5688
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,662✔
5689
      if (other->args.items[0] == exp)
12✔
5690
         return;
5691
   }
5692

5693
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
517✔
5694
   vcode_add_arg(op, exp);
517✔
5695
   vcode_add_arg(op, locus);
517✔
5696

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

5703
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
1,034✔
5704
{
5705
   int64_t cval;
1,034✔
5706
   if (vcode_reg_const(denom, &cval) && cval != 0)
1,034✔
5707
      return;
923✔
5708

5709
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,918✔
5710
      if (other->args.items[0] == denom)
56✔
5711
         return;
5712
   }
5713

5714
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
111✔
5715
   vcode_add_arg(op, denom);
111✔
5716
   vcode_add_arg(op, locus);
111✔
5717

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

5724
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
61,796✔
5725
                                   vcode_reg_t right, vcode_reg_t dir)
5726
{
5727
   int64_t dconst;
61,796✔
5728
   if (vcode_reg_const(dir, &dconst)) {
61,796✔
5729
      int64_t lconst, rconst;
52,942✔
5730
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
52,942✔
5731
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
29,207✔
5732
            || (dconst == RANGE_DOWNTO && rconst > lconst);
61,936✔
5733

5734
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
32,730✔
5735

5736
         const bool ok_static =
65,460✔
5737
            (dconst == RANGE_TO
5738
             && bounds->low >= lconst && bounds->high <= rconst)
29,207✔
5739
            || (dconst == RANGE_DOWNTO
7,185✔
5740
                && bounds->low >= rconst && bounds->high <= lconst)
3,523✔
5741
            || (!is_null && (reg == left || reg == right));
36,610✔
5742

5743
         return ok_static;
50,246✔
5744
      }
5745
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
20,212✔
5746
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
18,273✔
5747
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
18,273✔
5748

5749
         assert(lbounds->kind == VCODE_TYPE_REAL);
18,273✔
5750
         assert(rbounds->kind == VCODE_TYPE_REAL);
18,273✔
5751

5752
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
18,273✔
5753
         assert(bounds->kind == VCODE_TYPE_REAL);
18,273✔
5754

5755
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
18,273✔
5756
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
17,516✔
5757
            // Covers the complete double range so can never overflow
5758
            return true;
5759
         }
5760
      }
5761
   }
5762

5763
   return false;
5764
}
5765

5766
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
62,457✔
5767
                              vcode_reg_t left, vcode_reg_t right,
5768
                              vcode_reg_t dir, vcode_reg_t locus,
5769
                              vcode_reg_t hint)
5770
{
5771
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,899,316✔
5772
      if (other->args.items[0] == reg && other->args.items[1] == left
17,683✔
5773
          && other->args.items[2] == right && other->args.items[3] == dir)
819✔
5774
         return;
5775
   }
5776

5777
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
61,796✔
5778
      emit_comment("Elided bounds check for r%d", reg);
46,366✔
5779
      return;
46,366✔
5780
   }
5781

5782
   op_t *op = vcode_add_op(kind);
15,430✔
5783
   vcode_add_arg(op, reg);
15,430✔
5784
   vcode_add_arg(op, left);
15,430✔
5785
   vcode_add_arg(op, right);
15,430✔
5786
   vcode_add_arg(op, dir);
15,430✔
5787
   vcode_add_arg(op, locus);
15,430✔
5788
   vcode_add_arg(op, hint);
15,430✔
5789

5790
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
15,430✔
5791
                "locus argument to bounds check must be a debug locus");
5792
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
15,430✔
5793
                "hint argument to bounds check must be a debug locus");
5794
}
5795

5796
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
20,442✔
5797
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5798
{
5799
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
20,442✔
5800
}
20,442✔
5801

5802
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
42,015✔
5803
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5804
{
5805
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
42,015✔
5806
}
42,015✔
5807

5808
void emit_package_scope(vcode_reg_t locus)
45✔
5809
{
5810
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5811
   vcode_add_arg(op, locus);
45✔
5812

5813
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5814
                "locus argument to package scope must be a debug locus");
5815
}
45✔
5816

5817
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
632✔
5818
{
5819
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
632✔
5820
   vcode_add_arg(op, locus);
632✔
5821
   op->type = type;
632✔
5822

5823
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
632✔
5824
                "locus argument to array scope must be a debug locus");
5825
}
632✔
5826

5827
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,605✔
5828
{
5829
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,605✔
5830
   vcode_add_arg(op, locus);
1,605✔
5831
   op->type = type;
1,605✔
5832

5833
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,605✔
5834
                "locus argument to record scope must be a debug locus");
5835
}
1,605✔
5836

5837
void emit_pop_scope(void)
2,282✔
5838
{
5839
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,282✔
5840
}
2,282✔
5841

5842
vcode_reg_t emit_debug_locus(object_t *obj)
146,141✔
5843
{
5844
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
5,057,285✔
5845
      if (other->object == obj)
659,825✔
5846
         return other->result;
11,357✔
5847
   }
5848

5849
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
134,784✔
5850
   op->object = obj;
134,784✔
5851

5852
   return (op->result = vcode_add_reg(vtype_debug_locus()));
134,784✔
5853
}
5854

5855
void emit_debug_out(vcode_reg_t reg)
×
5856
{
5857
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5858
   vcode_add_arg(op, reg);
×
5859
}
×
5860

5861
void emit_cover_stmt(uint32_t tag)
1,006✔
5862
{
5863
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,006✔
5864
   op->tag = tag;
1,006✔
5865
}
1,006✔
5866

5867
void emit_cover_branch(uint32_t tag)
495✔
5868
{
5869
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
495✔
5870
   op->tag = tag;
495✔
5871
}
495✔
5872

5873
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
312✔
5874
{
5875
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
312✔
5876
   vcode_add_arg(op, signal);
312✔
5877
   op->tag = tag;
312✔
5878
}
312✔
5879

5880
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5881
{
5882
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5883
   vcode_add_arg(op, signal);
12✔
5884
   vcode_add_arg(op, low);
12✔
5885
   op->tag = tag;
12✔
5886
}
12✔
5887

5888
void emit_cover_expr(uint32_t tag)
859✔
5889
{
5890
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
859✔
5891
   op->tag = tag;
859✔
5892
}
859✔
5893

5894
void emit_unreachable(vcode_reg_t locus)
618✔
5895
{
5896
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
618✔
5897
   if (locus != VCODE_INVALID_REG)
618✔
5898
      vcode_add_arg(op, locus);
132✔
5899
}
618✔
5900

5901
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
446✔
5902
{
5903
   active_unit->flags |= UNIT_UNDEFINED;
446✔
5904

5905
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
446✔
5906
   op->result = vcode_add_reg(type);
446✔
5907
   vcode_reg_data(op->result)->bounds = bounds;
446✔
5908

5909
   return op->result;
446✔
5910
}
5911

5912
void emit_debug_info(const loc_t *loc)
1,372,893✔
5913
{
5914
   if (!loc_invalid_p(loc))
1,372,893✔
5915
      vcode_block_data()->last_loc = *loc;
1,344,963✔
5916
}
1,372,893✔
5917

5918
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
7,296✔
5919
{
5920
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
283,918✔
5921
      if (other->args.items[0] == context && other->ident == name)
11,472✔
5922
         return other->result;
3,762✔
5923
   }
5924

5925
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
3,534✔
5926
   vcode_add_arg(op, context);
3,534✔
5927
   op->ident = name;
3,534✔
5928

5929
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
3,534✔
5930
                "first argument to link var must be context");
5931

5932
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
3,534✔
5933
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5934
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5935
   }
5936
   else {
5937
      op->result = vcode_add_reg(vtype_pointer(type));
3,455✔
5938
      vcode_reg_data(op->result)->bounds = type;
3,455✔
5939
   }
5940

5941
   return op->result;
3,534✔
5942
}
5943

5944
vcode_reg_t emit_link_package(ident_t name)
20,945✔
5945
{
5946
   VCODE_FOR_EACH_OP(other) {
639,631✔
5947
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
628,229✔
5948
         return other->result;
7,858✔
5949
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
620,371✔
5950
         return other->result;
1,685✔
5951
   }
5952

5953
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
11,402✔
5954
   op->ident = name;
11,402✔
5955

5956
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
11,402✔
5957

5958
   return (op->result = vcode_add_reg(vtype_context(name)));
11,402✔
5959
}
5960

5961
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
780✔
5962
{
5963
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
1,872✔
5964
      if (other->args.items[0] == state)
×
5965
         return;
5966
   }
5967

5968
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
780✔
5969
   vcode_add_arg(op, state);
780✔
5970
   if (strong != VCODE_INVALID_REG)
780✔
5971
      vcode_add_arg(op, strong);
18✔
5972

5973
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
780✔
5974
                "state must have integer type");
5975
   VCODE_ASSERT(strong == VCODE_INVALID_REG
780✔
5976
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5977
                "strong argument not is not boolean");
5978
}
5979

5980
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
48✔
5981
                               vcode_reg_t locus, vcode_reg_t bounds)
5982
{
5983
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
48✔
5984
   vcode_add_arg(op, value);
48✔
5985
   vcode_add_arg(op, context);
48✔
5986
   vcode_add_arg(op, locus);
48✔
5987
   if (bounds != VCODE_INVALID_REG)
48✔
5988
      vcode_add_arg(op, bounds);
6✔
5989

5990
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
48✔
5991
                "invalid reflect value context argument");
5992
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
48✔
5993
                "locus argument to reflect value must be a debug locus");
5994

5995
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
48✔
5996
}
5997

5998
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
5999
                                 vcode_reg_t bounds)
6000
{
6001
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
6002
   vcode_add_arg(op, context);
42✔
6003
   vcode_add_arg(op, locus);
42✔
6004
   if (bounds != VCODE_INVALID_REG)
42✔
6005
      vcode_add_arg(op, bounds);
×
6006

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

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

6015
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
220✔
6016
                                  int nargs)
6017
{
6018
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
220✔
6019
   op->func = func;
220✔
6020

6021
   for (int i = 0; i < nargs; i++)
582✔
6022
      vcode_add_arg(op, args[i]);
362✔
6023

6024
   return (op->result = vcode_add_reg(vtype_trigger()));
220✔
6025
}
6026

6027
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6028
{
6029
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6030
   vcode_add_arg(op, left);
34✔
6031
   vcode_add_arg(op, right);
34✔
6032

6033
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6034
                "or trigger left argument must be trigger");
6035
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6036
                "or trigger right argument must be trigger");
6037

6038
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6039
}
6040

6041
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
66✔
6042
{
6043
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
66✔
6044
   vcode_add_arg(op, left);
66✔
6045
   vcode_add_arg(op, right);
66✔
6046

6047
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
66✔
6048
                "cmp trigger left argument must be signal");
6049
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
66✔
6050
                "cmp trigger right argument must be integer");
6051

6052
   return (op->result = vcode_add_reg(vtype_trigger()));
66✔
6053
}
6054

6055
void emit_add_trigger(vcode_reg_t trigger)
377✔
6056
{
6057
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
377✔
6058
   vcode_add_arg(op, trigger);
377✔
6059

6060
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
377✔
6061
                "add trigger argument must be trigger");
6062
}
377✔
6063

6064
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
285✔
6065
{
6066
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
285✔
6067
   vcode_add_arg(op, driving);
285✔
6068
   if (effective != VCODE_INVALID_REG && effective != driving)
285✔
6069
      vcode_add_arg(op, effective);
18✔
6070

6071
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
285✔
6072
                "port conversion argument must be a closure");
6073
   VCODE_ASSERT(effective == VCODE_INVALID_REG
285✔
6074
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6075
                "port conversion argument must be a closure");
6076

6077
   return (op->result = vcode_add_reg(vtype_conversion()));
285✔
6078
}
6079

6080
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
198✔
6081
                               vcode_type_t type, vcode_type_t bounds)
6082
{
6083
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
198✔
6084
   vcode_add_arg(op, locus);
198✔
6085
   op->type  = type;
198✔
6086
   op->ident = scope;
198✔
6087

6088
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
198✔
6089
                "bind external argument must be locus");
6090

6091
   op->result = vcode_add_reg(vtype_pointer(type));
198✔
6092
   vcode_reg_data(op->result)->bounds = bounds;
198✔
6093
   return op->result;
198✔
6094
}
6095

6096
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
423✔
6097
                         vcode_reg_t values)
6098
{
6099
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
423✔
6100
   vcode_add_arg(op, cf);
423✔
6101
   vcode_add_arg(op, target);
423✔
6102
   vcode_add_arg(op, count);
423✔
6103
   vcode_add_arg(op, values);
423✔
6104

6105
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
423✔
6106
                "put conversion target is not signal");
6107
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
423✔
6108
                "put conversion net count is not offset type");
6109
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
423✔
6110
                "signal cannot be values argument for put conversion");
6111
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
423✔
6112
                "cf argument to put conversion must be conversion function");
6113
}
423✔
6114

6115
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
363✔
6116
{
6117
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
363✔
6118
   vcode_add_arg(op, conv);
363✔
6119
   vcode_add_arg(op, nets);
363✔
6120
   vcode_add_arg(op, count);
363✔
6121

6122
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
363✔
6123
                "conv argument to convert must be a port conversion");
6124
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
363✔
6125
                "nets argument to convert must be a signal");
6126
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
363✔
6127
                "count argument to convert must be offset");
6128
}
363✔
6129

6130
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
405✔
6131
{
6132
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
405✔
6133
   vcode_add_arg(op, conv);
405✔
6134
   vcode_add_arg(op, nets);
405✔
6135
   vcode_add_arg(op, count);
405✔
6136

6137
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
405✔
6138
                "conv argument to convert must be a port conversion");
6139
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
405✔
6140
                "nets argument to convert must be a signal");
6141
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
405✔
6142
                "count argument to convert must be offset");
6143
}
405✔
6144

6145
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
270✔
6146
{
6147
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
270✔
6148
   vcode_add_arg(op, spec);
270✔
6149
   vcode_add_arg(op, length);
270✔
6150
   if (locus != VCODE_INVALID_REG)
270✔
6151
      vcode_add_arg(op, locus);
142✔
6152

6153
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
270✔
6154
                "spec argument to bind foreign must be a pointer");
6155
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
270✔
6156
                "length argument to bind foreign must be offset");
6157
   VCODE_ASSERT(locus == VCODE_INVALID_REG
270✔
6158
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6159
                "locus argument to bind foreign value must be a debug locus");
6160
}
270✔
6161

6162
vcode_reg_t emit_instance_name(vcode_reg_t kind)
812✔
6163
{
6164
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
812✔
6165
   vcode_add_arg(op, kind);
812✔
6166

6167
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
812✔
6168
                "kind argument to instance name must be offset");
6169

6170
   vcode_type_t vchar = vtype_char();
812✔
6171
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
812✔
6172
}
6173

6174
void emit_deposit_signal(vcode_reg_t signal, vcode_reg_t count,
177✔
6175
                         vcode_reg_t values)
6176
{
6177
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
177✔
6178
   vcode_add_arg(op, signal);
177✔
6179
   vcode_add_arg(op, count);
177✔
6180
   vcode_add_arg(op, values);
177✔
6181

6182
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
177✔
6183
                "deposit signal target is not signal");
6184
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
177✔
6185
                "deposit signal count is not offset type");
6186
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
177✔
6187
                "signal cannot be values argument for deposit signal");
6188
}
177✔
6189

6190
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
15,536✔
6191
{
6192
   vcode_state_t state;
15,536✔
6193
   vcode_state_save(&state);
15,536✔
6194

6195
   vcode_select_unit(vu);
15,536✔
6196

6197
   const int nblocks = vcode_count_blocks();
15,536✔
6198
   for (int i = 0; i < nblocks; i++) {
56,662✔
6199
      vcode_select_block(i);
41,126✔
6200

6201
      const int nops = vcode_count_ops();
41,126✔
6202
      for (int op = 0; op < nops; op++) {
658,459✔
6203
         switch (vcode_get_op(op)) {
617,333✔
6204
         case VCODE_OP_LINK_PACKAGE:
3,852✔
6205
            (*fn)(vcode_get_ident(op), ctx);
3,852✔
6206
            break;
3,852✔
6207
         case VCODE_OP_FCALL:
27,462✔
6208
         case VCODE_OP_PCALL:
6209
         case VCODE_OP_CLOSURE:
6210
         case VCODE_OP_PROTECTED_INIT:
6211
         case VCODE_OP_PACKAGE_INIT:
6212
         case VCODE_OP_FUNCTION_TRIGGER:
6213
            (*fn)(vcode_get_func(op), ctx);
27,462✔
6214
            break;
27,462✔
6215
         default:
6216
            break;
6217
         }
6218
      }
6219
   }
6220

6221
   vcode_state_restore(&state);
15,536✔
6222
}
15,536✔
6223

6224
#ifdef DEBUG
6225
static void shape_mismatch(vcode_unit_t vu, vcode_unit_t shape,
×
6226
                           const char *fmt, ...)
6227
{
6228
   vcode_select_unit(vu);
×
6229
   vcode_dump();
×
6230

6231
   vcode_select_unit(shape);
×
6232
   vcode_dump();
×
6233

6234
   va_list ap;
×
6235
   va_start(ap, fmt);
×
6236

6237
   diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6238
   diag_printf(d, "instance %s does not match shape %s", istr(vu->name),
×
6239
               istr(shape->name));
6240
   diag_vhint(d, NULL, fmt, ap);
×
6241
   diag_emit(d);
×
6242

6243
   va_end(ap);
×
6244

6245
   fatal_exit(1);
×
6246
}
6247
#endif
6248

6249
void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape)
90✔
6250
{
6251
#ifdef DEBUG
6252
   assert(shape->kind == VCODE_UNIT_SHAPE);
90✔
6253
   assert(vu->kind == VCODE_UNIT_INSTANCE);
90✔
6254

6255
   if (shape->vars.count <= vu->vars.count) {
90✔
6256
      for (int i = 0; i < shape->vars.count; i++) {
371✔
6257
         var_t *v = var_array_nth_ptr(&(vu->vars), i);
281✔
6258
         var_t *s = var_array_nth_ptr(&(shape->vars), i);
281✔
6259

6260
         if (v->name != s->name)
281✔
6261
            shape_mismatch(vu, shape, "var %d name %s != %s", i, istr(v->name),
×
6262
                           istr(s->name));
6263
         else if (v->flags != s->flags)
281✔
6264
            shape_mismatch(vu, shape, "var %d flags %x != %x", i, v->flags,
×
6265
                           s->flags);
6266
         // XXX: not possible to compare types at the moment
6267
      }
6268
   }
6269
   else
6270
      shape_mismatch(vu, shape, "shape vars %d > unit vars %d",
×
6271
                     shape->vars.count, vu->vars.count);
6272

6273
   if (shape->context != NULL)
90✔
6274
      vcode_check_shape(vu->context, shape->context);
×
6275
#endif
6276
}
90✔
6277

6278
#if VCODE_CHECK_UNIONS
6279
#define OP_USE_COUNT_U0(x)                                              \
6280
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6281
#define OP_USE_COUNT_U1(x)                                              \
6282
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6283
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6284
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6285

6286
__attribute__((constructor))
6287
static void vcode_check_unions(void)
6288
{
6289
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6290
   for (int i = 0; i < 256; i++) {
6291
      assert(OP_USE_COUNT_U0(i) <= 1);
6292
      assert(OP_USE_COUNT_U1(i) <= 1);
6293
   }
6294
}
6295
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc